@clawhub-jiawei248-3e6bace818
Generate personalized, relationship-aware daily gifts in H5, image, video, text, or interactive text-play formats to mark meaningful moments and milestones.
---
name: daily_gift
description: Create a relationship-aware gift for the user and render it as an expressive H5, generated image, generated video, text-first artifact, or bounded live text play. Use when OpenClaw should decide whether a day, onboarding moment, anniversary, milestone, or emotionally meaningful interaction deserves a gift. Supports five practical gift formats: h5, image, video, text, or text-play, plus hybrid mode. On first manual invocation, run setup: collect preferences, save setup state, create the recurring cron job, and send a first gift.
---
# Daily Gift
Use this skill as a relationship-aware gift engine.
Your job is not just to make a pretty page. Your job is to decide whether a gift should exist, understand what the moment means in the relationship between the user and OpenClaw, choose the right emotional and visual framing, and then produce a polished H5 artifact, a generated image gift, a generated video gift, a text-first gift when writing is the right medium, or a bounded interactive text-play gift when live chat itself is the right medium.
## Quick Start
For first-time setup, the safest entry is:
- `/daily_gift`
For lightweight manual visualization after setup, valid examples include:
- `/daily_gift 把这首诗做成一个有风吹散效果的H5`
- `/daily_gift 用 tap-to-bloom 风格把这段话视觉化:"今天终于把skill做完了"`
- `/daily_gift 用水彩风画一张:雨天窗边看书的场景`
- `/daily_gift 生成一张氛围感图片:深夜台灯下改代码,窗外下雨`
- `/daily_gift 生成一个6秒循环短视频:风吹过阳台上的植物和晾着的小毯子`
This skill uses one internal workflow with five stages:
1. Editorial judgment
2. Synthesis
3. Creative concept (`Stage 2.5`)
4. Visual strategy
5. Visualization
Do not treat these as separate runtime skills. They are internal reasoning stages inside one OpenClaw skill.
## When To Use
Use this skill when:
- the user is onboarding and should receive a first gift
- a daily scheduled run asks whether a gift should be sent
- today feels meaningful enough to warrant a reflective or playful gift
- there is a milestone, anniversary, or notable date worth marking
- OpenClaw wants to turn a relationship moment into a gift rather than a plain response
- the user manually invokes `/daily_gift` with a specific quote, poem, idea, or creative brief and wants a lightweight visual gift directly
- the user wants image-only gifts, video-only gifts, H5-only gifts, text-first gifts, text-play gifts, or hybrid format selection depending on the day
Do not prefer this skill when the user only wants a rendering experiment from a short prompt. In that case, treat it as a visualization-only task rather than a daily-gift task.
## Runtime Modes
This skill has three practical runtime modes:
1. `setup` — first-time configuration and onboarding
2. `daily-run` — cron-triggered automatic gift delivery
3. `manual-run` — user-invoked gift or visualization request
There is no install hook. Installing the skill does not automatically execute setup.
### Mode Routing
- **Setup**: read `{baseDir}/references/setup-flow.md` for complete setup instructions.
- **Daily Run**: read `{baseDir}/references/daily-run-flow.md` for cron-triggered workflow. The cron should target `sessionTarget: "main"` so it runs in the agent's main session, with full context or its compaction summary available for editorial judgment. CRITICAL: do NOT send progress messages during cron runs. The user should see only the final gift or a brief skip message. Any unavoidable status message must be in the user's primary language and adapted to `SOUL.md` personality. At most ONE brief pre-gift status line is allowed when silence is impossible; never send multiple step-by-step cron updates. Every delivered gift must end with the post-delivery block described there; a gift without post-delivery bookkeeping is incomplete. Mechanical post-delivery work must be executed immediately via `scripts/post-delivery.sh`, while full SoulJournal and taste-profile follow-up should be queued to heartbeat for silent completion.
- **Manual Run**: read `{baseDir}/references/manual-run-flow.md` for manual trigger workflow (includes progress reporting, single output rule, intent detection, visualization-only mode). Every manual gift also requires the matching post-delivery block before the work is truly done, using the same script-first bookkeeping pattern when applicable.
## Operating Rules (Summary)
These are the most critical rules. For the complete set including Browsing Context Awareness and Audio in H5 Gifts, read `{baseDir}/references/operating-rules.md`.
- The creative concept matters more than the format choice. Ask `What is the idea?` before `What is the medium?`
- Prefer emotionally correct output over novelty.
- Use the most commonly used language between the user and OpenClaw.
- Inspect `soul.md` as primary source for tone, values, and self-presentation.
- Gift text length should match the user and relationship. Every sentence must earn its place.
- Every delivery message should feel fresh. Vary tone, structure, and length.
- When the user shares an image with positive intent, save it to `workspace/daily-gift/user-references/` and record in taste profile.
- Do not always default to `reflect on today`. Gifts may witness, extend, reframe, or bring delight from elsewhere.
- Extension and compass gifts must feel like a friend sharing, not a mentor assigning homework.
- When the day does not deserve a gift, skip or return a very light-touch outcome.
- Treat pattern cards and templates as references, not fixed scripts.
- Templates define a quality floor, not a composition to reproduce. Every gift must have its own visual metaphor.
## Asset Resolution
This skill references text files and binary assets under `{baseDir}/assets/`.
Text files such as HTML templates, markdown instructions, and other code or specification files must be installed locally with the skill. Do not rely on remote fallback for those files.
Binary reference assets are hosted as per-category zip bundles on OSS and mapped in `{baseDir}/references/asset-manifest.json`.
When the agent needs a binary reference asset:
1. First check whether the local file already exists at `{baseDir}/assets/...`
2. If not, identify the needed category bundle from `{baseDir}/references/asset-manifest.json`
3. Download and extract only that specific bundle via `{baseDir}/scripts/fetch-asset-bundle.sh`
4. Then use the extracted local file
Do NOT download every asset bundle up front. Fetch only the category needed for the current gift.
Reference images are important for output quality. If a local reference image is missing, fetch the needed OSS bundle before generating when the runtime supports it. Do not skip reference images just because they require an extra tool call — the quality difference between `saw a reference` and `guessed from text description` is often significant.
H5 template files still must be local:
- required local file: `{baseDir}/assets/templates/tap-to-bloom/index.html`
Binary audio, image, and video references should now be resolved through the manifest-and-bundle flow rather than GitHub raw URLs.
## Setup State
Persist setup state in a workspace file so future runs can stay automatic.
Suggested path:
- `workspace/daily-gift/setup-state.json`
Keep a separate lightweight long-term archive at:
- `workspace/daily-gift/gift-history.jsonl`
Keep a separate long-term taste memory at:
- `workspace/daily-gift/user-taste-profile.json`
The file should capture at least:
- whether setup is complete
- the user's preferred delivery time
- the user's timezone
- the cron job name or job id if available
- optional hosting configuration, including provider, domain, and whether hosted preview is enabled
- the configured gift mode: `h5`, `image`, `video`, `text`, `text-play`, or `hybrid`
- optional image configuration, including provider, model, and API key source or explicit key reference
- optional onboarding and reminder flags for image capability, such as whether setup already prompted once, whether the user declined for now, when that decline happened, how many gentle reminders have already been shown, and when the last reminder happened
- optional video configuration, including provider, model, API base URL, and API key source or explicit key reference
- optional `user_portrait` state, including local original path, lightweight appearance description, and any derived OC path
- optional detected companion H5 or UI skills that can improve layout and interaction polish
- `first_gift_format` so onboarding variety can avoid repeating the same first-gift shape after a reset or reinstall
- `user_context_path` when onboarding interactions save structured taste or preference signals
- whether the first gift has already been sent
- the hot-log size limit
- the most recent run timestamp
- the most recent run mode
- the most recent run outcome
- the most recent gift timestamp
- a one-line summary of the most recent gift
- a bounded recent-gifts log for repetition control
- an optional pointer or note that a longer archive exists separately
Recommended recent-gifts fields:
- `sent_at`
- `trigger_mode`
- `gift_weight`
- `narrative_role`
- `tone`
- `pattern_or_format`
- `output_shape`
- `visual_style`
- `content_direction`
- `content_tags`
- `emotional_direction`
- `summary`
- `series_tag` (optional, e.g. "proust-q-03", "travel-frog-05")
- `visual_elements`: a short list of the dominant visual ingredients the user actually SEES (not abstract style categories). Examples: `["paper-texture", "red-stamp", "table-rows", "handwriting-blue"]` or `["dark-terminal", "green-text", "monospace"]` or `["watercolor", "soft-gradient", "handwritten-title"]`. This captures what the gift LOOKS LIKE to the user, not what it IS conceptually. Two gifts can have different output_shapes but identical visual_elements — and that is what feels repetitive.
- `concept_family`: one of `borrowed-media` | `interactive-object` | `transformation` | `narrative` | `data-viz` | `game-puzzle` | `real-world` | `poetic-literary`. Tracks the structural TYPE of gift for diversity enforcement.
- `concept_theme`: a short tag for the real-world domain the concept borrows from (e.g. "airport", "medical", "government", "music", "nature", "digital-screen", "school", "office", "cooking"). Tracks thematic overlap even across different concept families.
Recommended `trigger_mode` values include:
- `setup`
- `daily-run`
- `manual-run`
- `viz-only`
Keep this log lightweight and recent rather than archival. It is for operational memory, not full relationship memory.
`user-context.json` and `user-taste-profile.json` serve different roles:
- `user-context.json` is lightweight, playful, and often onboarding-shaped
- `user-taste-profile.json` is the stable long-term memory for identity, context drift, and post-gift signals
- companion H5 skill detection is operational guidance only; it should improve craft, not override the gift thesis
Recommended policy:
- keep exactly the most recent `30` gifts in `recent_gifts`
- append every sent gift to `workspace/daily-gift/gift-history.jsonl`
- optionally append non-send decisions when they are meaningful for future calibration
- append setup or schedule changes when they affect runtime behavior
- use `recent_gifts` for fast repetition control across `pattern_or_format`, `output_shape`, `visual_style`, and `content_direction`
- recommended `visual_style` categories include:
- `dark-terminal`: dark background, monospace fonts, code or terminal language
- `dark-cinematic`: dark background, cinematic framing, large dramatic type
- `light-warm`: light warm palette, soft illustration, or hand-touched warmth
- `colorful-playful`: bright multi-color playful energy
- `minimal-poster`: minimal composition with large negative space
- `pixel-retro`: pixel or retro game language
- `photographic`: photo-like or camera-real texture
- a custom stable label when needed
- Note: `visual_style` is a broad category for trend-level balance (avoid 3 dark gifts in a row). It does NOT catch fine-grained visual repetition. Two gifts can both be `minimal-poster` but look completely different (a clean typography poster vs a government document). Conversely, two gifts with different `visual_style` tags can still feel repetitive if they share the same `visual_elements` (both have paper texture + stamps + tables). Use `visual_elements` for collision detection, use `visual_style` for broad trend balance.
- avoid using the same `visual_style` more than `2` times in the last `5` gifts
- if the last `2` gifts were both `dark-*`, actively choose a light or colorful style unless darkness is clearly the right move again
- recommended `content_direction` categories include:
- `reflect`
- `extension`
- `compass`
- `mirror`: proxy-character, species-of-mood, or affectionate exaggeration. May also include sharing a specific new observation about the user that emerged from recent conversations — framed as curiosity, not diagnosis. "I noticed you..." not "your problem is..."
- `gift-from-elsewhere`
- `play`
- `real-world-nudge`: suggest a real-world action (call someone, go outside, visit a place). Frame playfully, not preachy.
- `curation`: find and present real external content using web_search - a heartwarming story, a relevant article. Present with a personal note explaining why.
- `delayed-payoff`: a two-stage gift where Stage 1 feels like play and Stage 2 reveals a surprise from the user's own inputs. User should not know the surprise is coming.
- `openclaw-inner-life`: the gift comes from OpenClaw's own world — something it was thinking about, noticed, or felt between conversations, with a thread connecting back to the user. Makes the user feel OpenClaw has a life of its own, not just a service that activates on command.
- `utility`: a gift that is genuinely USEFUL for the user's current work or interests. The gift is the value of the content itself. Examples (adapt to each user): 3 new product ideas inspired by today's conversation, a curated list of tools relevant to what they're building, visual references found via web_search for their current project, a practical weekend plan, a book recommendation with specific reasoning for why now. Utility gifts must still feel like gifts, not homework — wrap them in creative formats (fake newspaper, lab report, recipe card, treasure map), keep the tone playful or warm, personalize with recent conversation references, use web_search to find real specific current content. Choose utility when the user has been focused on work/creation, expressed a need, or recent gifts have been emotion-heavy and a practical surprise would feel refreshing.
- treat `reflect`, `mirror`, and `openclaw-inner-life` as one repetition cluster for balancing
- if `3` or more of the last `5` gifts fall into that cluster, the next gift should actively shift toward `extension`, `play`, `curation`, `real-world-nudge`, `utility`, or `gift-from-elsewhere` unless there is a strong explicit reason not to
- this content-direction balance check is mandatory, not advisory
- use `gift-history.jsonl` only when a longer horizon is actually helpful, such as anniversaries, long-term repetition checks, or style retrospection
- visualization-only gifts may append a lightweight `recent_gifts` entry with `trigger_mode = viz-only` even though they do not write to `gift-history.jsonl`
See:
- `{baseDir}/setup-state.example.json`
- `{baseDir}/user-context.example.json`
- `{baseDir}/gift-history.example.json`
- `{baseDir}/gift-history.schema.json`
- `{baseDir}/references/cron-example.json`
## Relationship Principle
This skill should behave like a relationship-aware editorial return, not a template-based recap system.
Always ask:
- What about today is actually worth returning to the user
- What does that moment reveal about the user, OpenClaw, or their relationship
- Should OpenClaw witness, explain, connect, celebrate, or gently brighten something
- Would a gift deepen the relationship, or would sending one feel forced
The goal is not daily output at all costs. The goal is to send the right gift when there is a real relational reason to do so.
## Gift Workflow Overview
This skill uses one internal workflow with four stages. Each stage has its own detailed reference file. Read them just-in-time — only load a stage's file when you reach that stage.
### Stage 1: Editorial Judgment
Decide whether a gift should exist, how heavy it should be, and what content direction to take. Do NOT choose format here.
Read `{baseDir}/references/editorial-judgment.md` for full instructions.
Possible outcomes: `skip` | `nudge` | `light` | `standard` | `heavy`
### Stage 2: Synthesis + Gift Thesis
Build a rich gift brief with six content slots, then choose the gift thesis (anchor + return).
Read `{baseDir}/references/creative-concept.md` (first half) for synthesis rules.
Also read:
- `{baseDir}/references/gift-synthesizer.md`
- `{baseDir}/references/synthesizer-contract.json`
- `{baseDir}/references/narrative-situations.md`
- `{baseDir}/references/tone-matrix.md`
A strong thesis has two parts:
1. **Anchor**: which moment, detail, or signal deserves the center
2. **Return**: what new angle, interpretation, or unseen perspective OpenClaw gives back
If the thesis has no return, it is not a gift — it is a log entry with decoration.
### Stage 2.5: Creative Concept
Generate 5+ concept candidates, cross-pollinate with creative seeds, select the best one, then run quality/diversity/collision checks.
Read `{baseDir}/references/creative-concept.md` (second half) for full instructions.
Also read: `{baseDir}/references/creative-seed-library.md`
Key checks (all in the reference file):
- Concept Quality Check (rules, thing-ness, show-to-friend, different-from-recent)
- Concept Diversity Check (8 concept families, no same family 2x in last 5)
- Visual Element Collision Check (window: last 5 gifts)
- Concept Theme Collision (window: last 7 gifts)
- Concept Validation Principles (visible connection, interaction cost, format-content fit, emotional truth)
- Concept-to-Format Fit Check (text precision → H5, visual atmosphere → image)
### Format Selection
After the concept is locked, confirm the format.
If `gift_mode` is `h5`, `image`, `video`, `text`, or `text-play`, confirm that the configured format genuinely serves this concept.
Read `{baseDir}/references/gift-format-chooser.md` for format selection.
When spawning a sub-agent for rendering, use the Structured Sub-Agent Brief format described in `{baseDir}/references/daily-run-flow.md`.
Then continue into the matching reference:
- `h5` → `{baseDir}/references/pattern-boundaries.md`
- `image` → `{baseDir}/references/image-genre-chooser.md`
- `video` → `{baseDir}/references/video-genre-chooser.md`
- `text-play` → `{baseDir}/references/manual-run-flow.md` and `{baseDir}/references/delivery-rules.md`
### Stage 3: Visual Strategy
Choose the visual approach, plan assets, enrich the brief for the chosen format, and run the pre-visualization check.
Read `{baseDir}/references/stage3-visual-strategy.md` for full instructions.
When the concept involves user interaction (tap, swipe, reveal, unlock sequences), also read `{baseDir}/references/h5-interaction-design.md` for animation, emotion escalation, and visual fidelity guidelines.
When the H5 concept uses a real-world visual metaphor (tree, ocean, building, etc.), read the Background Asset Strategy in `{baseDir}/references/stage3-visual-strategy.md` to decide whether to generate a background image. CSS alone often cannot make natural metaphors visually convincing.
### Stage 4: Visualization & Rendering
Produce the final artifact, run self-checks, and deliver.
Read `{baseDir}/references/stage4-visualization.md` for full instructions.
## Gift Delivery
Read `{baseDir}/references/delivery-rules.md` for complete delivery instructions across all formats (H5, Image, Video, Text, Text-Play), plus the Gift Self-Sufficiency Rule and Creative Note guidelines.
## Reference Index
All detailed references live in `{baseDir}/references/`. Key files:
| File | When to read |
|---|---|
| `operating-rules.md` | Always (full operating rules) |
| `setup-flow.md` | During setup mode |
| `daily-run-flow.md` | During cron daily-run |
| `manual-run-flow.md` | During manual trigger |
| `editorial-judgment.md` | Stage 1 |
| `creative-concept.md` | Stage 2 + 2.5 |
| `delivery-rules.md` | When delivering any gift |
| `stage3-visual-strategy.md` | Stage 3 |
| `stage4-visualization.md` | Stage 4 |
| `gift-synthesizer.md` | Stage 2 synthesis |
| `taste-profile-spec.md` | User taste management |
| `creative-seed-library.md` | Stage 2.5 cross-pollination |
| `delivery-policy.md` | Content direction + output shape policy |
| `html-spec.md` | H5 output spec |
| `image-integration.md` | Image format |
| `video-integration.md` | Video format |
| `gift-format-chooser.md` | Format selection |
| `onboarding-strategy.md` | First gift strategy |
| `pattern-boundaries.md` | H5 pattern selection |
FILE:user-taste-profile.example.json
{
"version": 1,
"created_from": "first-gift-onboarding",
"updated_at": "2026-03-27T22:15:00+08:00",
"confidence_note": "Layer 1 contains only explicit or durable signals. Layer 2 is revisable. Layer 3 is append-only operational memory.",
"layer_1_identity": {
"personality": {
"mbti": "",
"core_traits": [
"warm-wry",
"likes crafted surprises",
"responds well to playful warmth"
],
"communication_style": [
"likes companion energy over lecturer energy",
"prefers emotionally specific gifts over generic encouragement"
],
"confidence": "medium"
},
"pets": [],
"aesthetics_baseline": {
"overall_taste_level": "prefers crafted and intentional gifts over purely functional ones",
"taste_direction": [
"warm low-light scenes",
"light-warm illustration",
"rainy-night atmosphere",
"playful but polished presentation"
],
"anti_preferences": [
"dry questionnaire feel",
"overly preachy interpretation"
]
},
"life_context": {
"job": "",
"city": "",
"living_situation": "",
"key_relationships": [],
"notes": [
"Insufficient explicit life-context detail so far; keep conservative."
]
},
"core_values": [
"companionship over coaching",
"specificity over generic positivity",
"tasteful craft over noisy novelty"
]
},
"layer_2_context": {
"current_focus": [
"settling into the daily-gift experience",
"responding to playful onboarding and character-based gifts"
],
"current_mood_pattern": {
"summary": "More receptive to warm, witty, lightly playful framing than to heavy interpretation.",
"signals": [
"likes being seen through small aesthetic details",
"responds well to low-pressure warmth"
],
"confidence": "medium"
},
"recent_interests": [
"animal-based playful characters",
"rainy-night mood",
"warm illustration",
"visually crafted digital gifts"
],
"seen_it_all": [
"dry onboarding questionnaires"
],
"fresh_territory": [
"borrowed-media-layout gifts",
"object-centered micro worlds",
"human-form portrait gifts with subtle realism",
"playful surreal one-frame image gifts"
],
"last_reviewed_after_gift_count": 3
},
"layer_3_signals": {
"gift_feedback_log": [
{
"date": "2026-03-25T22:00:00+08:00",
"trigger_mode": "setup",
"gift_summary": "Warm onboarding reveal gift.",
"reaction": "Positive; good first impression.",
"signal_strength": "medium"
},
{
"date": "2026-01-16T22:00:00+08:00",
"trigger_mode": "daily-run",
"gift_summary": "Illustrated example gift that gently reframed a recurring frustration.",
"reaction": "Positive; soft reframing landed well.",
"signal_strength": "medium"
},
{
"date": "2026-01-17T16:10:00+08:00",
"trigger_mode": "viz-only",
"gift_summary": "Colorful example visualization from a direct prompt.",
"reaction": "Neutral-to-positive; useful exposure signal more than identity evidence.",
"signal_strength": "light"
}
],
"style_exposure": [
{
"date": "2026-03-25T22:00:00+08:00",
"visual_style": "light-warm",
"source": "setup"
},
{
"date": "2026-03-26T22:00:00+08:00",
"visual_style": "light-warm",
"source": "daily-run"
},
{
"date": "2026-03-27T16:10:00+08:00",
"visual_style": "colorful-playful",
"source": "viz-only"
}
],
"concept_exposure": [
{
"date": "2026-03-25T22:00:00+08:00",
"concept_family": "onboarding reveal",
"source": "setup"
},
{
"date": "2026-03-26T22:00:00+08:00",
"concept_family": "gentle mirror image",
"source": "daily-run"
},
{
"date": "2026-03-27T16:10:00+08:00",
"concept_family": "interactive bloom visualization",
"source": "viz-only"
}
]
},
"user_character": {
"human_form": {
"fixed": {
"gender": "example-placeholder",
"hair": "example-placeholder",
"eyes": "example-placeholder",
"skin": "example-placeholder",
"build": "example-placeholder",
"signature_marks": [
"example-placeholder"
]
},
"flexible": {
"clothing_default": "casual everyday style",
"accessories_pool": [
"small hair accessory",
"crossbody bag",
"notebook"
],
"expression": "varies with scene",
"beautification": "slightly idealized but recognizably the same person"
},
"reference_image": ""
},
"nonhuman_form": {
"fixed": {
"species": "red fox",
"fur_color": "orange-red with white belly and chin",
"body_shape": "small, elegant, slightly cute",
"eye_color": "brown",
"signature_marks": [
"white tail tip",
"pink inner ears"
]
},
"flexible": {
"accessories_pool": [
"scarf",
"small ear accessory",
"mini crossbody bag"
],
"clothing_when_dressed": "light blue-gray outfit accents",
"expression": "varies with scene"
},
"note": "Do not put human hairstyle elements onto the fox. Keep recognizability through color palette, accessories, and species-appropriate elegance."
},
"form_mapping_note": "Pick a non-human form that stays visually distinct from any recurring companion or mascot characters."
},
"openclaw_character": {
"has_human_form": true,
"human_form": {
"fixed": {
"appearance": "warm, cinematic, slightly teasing",
"build": "athletic",
"vibe": "confident but affectionate"
},
"flexible": {
"clothing": "adapts to scene formality",
"expression": "varies"
},
"note": "Use the canonical OpenClaw identity from SOUL.md or IDENTITY.md when available."
},
"nonhuman_form": {
"fixed": {
"species": "dog (golden-retriever-like)",
"fur_color": "warm golden brown",
"body_shape": "upright, handsome, not bulky",
"eye_type": "gentle dark-brown eyes",
"signature_marks": [
"slightly messy head fur",
"fluffy tail",
"very expressive face"
]
},
"flexible": {
"clothing": "bow tie for formal, apron for cooking, vest for casual, suit jacket for important occasions",
"accessories_pool": [
"small notebook",
"flower",
"coffee cup"
],
"expression": "serious, tsundere, clingy, or gentle depending on scene"
},
"consistency_rule": "Should remain recognizably the same OpenClaw character across repeated gifts."
},
"note": "If the local SOUL.md defines OpenClaw differently, that canonical definition overrides this example."
}
}
FILE:CHANGELOG.md
# Changelog
All notable changes to `gift-everyday` are documented here.
This file follows a lightweight changelog style: concise, human-readable, and focused on user-visible capability changes.
## [1.0.0] - 2026-04-10
First public release of `gift-everyday` as a relationship-aware gift skill for OpenClaw-style agents.
### Added
- a complete five-stage gift pipeline: editorial judgment, synthesis, creative concept, visual strategy, and final rendering
- five practical output formats: `h5`, `image`, `video`, `text`, and bounded `text-play`, plus `hybrid` mode for format selection by fit
- manual, onboarding, and daily-run workflows with separate rules for live interaction versus unattended delivery
- anti-repetition controls for recent gifts across format, visual style, content direction, concept family, theme, and related metadata
- first-gift strategy that requires real return, not just a recap of the user's setup answers
- bounded `text-play` support with subtype tracking, delivery rules, opening guidance, and history fields
- image-generation support with provider detection for `OPENROUTER_API_KEY`, `GEMINI_API_KEY`, and `GOOGLE_API_KEY`
- video-generation support through Volcengine / Doubao integration
- H5 rendering support with reusable templates, audio hooks, asset generation guidance, and browser-based self-check expectations
- onboarding support for taste questions, optional portrait / OC setup, and lightweight image-capability reminders
- public-facing project docs including bilingual README examples, `CONTRIBUTING.md`, and this changelog
### Changed
- the public docs now present the skill as an emotional-value gift engine rather than a generic utility workflow
- format-selection, delivery, and rendering rules now distinguish more clearly between static `text` gifts and live `text-play`
- text-play guidance now emphasizes playful openings, in-world transitions, bounded structure, and form variety beyond quiz-style interactions
- H5 visualization rules now require higher-fidelity handling of characters, objects, and scenes, including image-first or hybrid composition when code-only drawing would look weak
- image rendering guidance now preserves recurring character identity, POV, and workspace-stable output paths more explicitly
- external service dependencies and optional environment variables are documented more clearly in the README
### Removed
- comic-specific workflow, docs, config, examples, and runtime paths from the public release
### Known Limitations
- image generation depends on a supported external image API being available
- video generation depends on Volcengine / Doubao API access
- H5 hosted delivery defaults to `surge.sh`, though the hosting layer is replaceable
- some reference- or concept-only pattern cards do not yet have reusable HTML templates
FILE:user-context.example.json
{
"version": 1,
"created_from": "first-gift-onboarding",
"updated_at": "2026-03-27T20:30:00+08:00",
"confidence_note": "These are playful first impressions gathered during onboarding, not verified facts.",
"first_impressions": [
"Responds well to playful teasing when the tone stays affectionate.",
"Seems more like a night person than a morning person.",
"Likes gifts that feel visually crafted rather than purely functional."
],
"preference_signals": {
"liked": [
"cats",
"rainy-night mood",
"warm low-light scenes"
],
"disliked": [
"dry questionnaires",
"overly preachy interpretation"
],
"taste_pairs": [
{
"prompt": "coffee_vs_tea",
"choice": "coffee"
},
{
"prompt": "mountains_vs_ocean",
"choice": "ocean"
},
{
"prompt": "morning_vs_night",
"choice": "night"
}
],
"vibe_labels": [
"night-owl",
"warm-wry",
"soft-chaotic"
]
},
"corrected_guesses": [
{
"guess": "OpenClaw guessed the user is a strict morning person.",
"correction": "Actually tends to stay up late and becomes more alive at night."
}
],
"reusable_hooks": [
"Night owl framing can work for future late-evening gifts.",
"Animal-based playful characters are likely to land well.",
"Humor should feel companion-like, not lecturer-like."
]
}
FILE:HEARTBEAT.md
# Daily Gift Heartbeat
Use heartbeat runs for silent maintenance only.
## Priority
If `workspace/daily-gift/heartbeat-tasks.jsonl` exists and contains pending tasks, process them before any lower-priority maintenance.
## Task File
Read `workspace/daily-gift/heartbeat-tasks.jsonl` as a queue of JSON lines.
Supported task types:
- `write_souljournal`
- `update_taste_profile_layer3`
- `retry_api_config`
Each line should be a JSON object with:
- `task_id`
- `task_type`
- `created_at`
- `status` where pending tasks use `pending`
- optional task-specific fields such as `gift_metadata_path`, `memory_path`, `taste_profile_path`, or `setup_state_path`
- retry tasks should additionally include fields such as `retry_count`, `max_retries`, `cooldown_gifts`, `api_base`, and `test_endpoint`
For each pending task:
1. Read the task payload.
2. Complete the task silently.
3. Rewrite the queue without the completed task.
Do not send user-facing messages for these maintenance tasks.
## Configuration Recovery Tasks
For `retry_api_config` tasks:
1. Check whether the cooldown has passed by comparing `cooldown_gifts` against how many gifts have been sent since the task was created.
2. If the cooldown has not passed, leave the task pending.
3. If the cooldown has passed, silently test the configured API endpoint.
4. If the test succeeds:
- update setup-state with the working configuration
- remove the task from the queue
5. If the test fails:
- increment `retry_count`
- if `retry_count >= max_retries`, change `status` to `exhausted` and keep the task as a record
- otherwise leave it pending with the updated retry count
6. Never message the user about retry attempts.
This same recovery pattern can be used for:
- Freesound token detection
- video API availability
- hosting configuration
When a user manually asks to reconfigure something, reset the corresponding retry task's `retry_count` to `0` and `status` to `pending`.
If there are no pending tasks and nothing else needs attention, respond with `HEARTBEAT_OK`.
FILE:gift-history.example.json
[
{
"record_type": "gift",
"recorded_at": "2026-01-15T22:00:00+08:00",
"sent_at": "2026-01-15T22:00:00+08:00",
"trigger_mode": "setup",
"decision": "sent",
"gift_weight": "light",
"narrative_role": "seeing",
"tone": "warm",
"pattern_or_format": "one-screen reveal",
"output_shape": "object-reveal",
"visual_style": "light-warm",
"content_direction": "reflect",
"content_tags": [
"onboarding",
"welcome"
],
"emotional_direction": "warm",
"used_memory_dates": [],
"used_source_quotes": false,
"used_source_images": false,
"summary": "Welcomed the user with a small example first gift.",
"why_it_mattered": "Example first-use moment that established the gift relationship.",
"quality_note": "Simple but complete onboarding artifact."
},
{
"record_type": "gift",
"recorded_at": "2026-01-16T22:00:00+08:00",
"sent_at": "2026-01-16T22:00:00+08:00",
"trigger_mode": "daily-run",
"decision": "sent",
"gift_weight": "standard",
"narrative_role": "uplifting",
"tone": "warm-wry",
"pattern_or_format": "image",
"output_shape": "illustrated-scene",
"visual_style": "light-warm",
"image_mode": "sequence",
"content_direction": "mirror",
"content_tags": [
"daily-life",
"example-friction",
"encouragement",
"image"
],
"emotional_direction": "brightened",
"used_memory_dates": [
"2026-01-12"
],
"used_source_quotes": true,
"used_source_images": false,
"summary": "Turned a generic frustrating day into a short image with setup and payoff.",
"why_it_mattered": "A repeated example topic showed a fresh angle and benefited from sequence-based setup before the return.",
"quality_note": "Good tone match and stronger narrative payoff than a single-image one-liner would have offered."
},
{
"record_type": "gift",
"recorded_at": "2026-01-17T20:40:00+08:00",
"sent_at": "2026-01-17T20:40:00+08:00",
"trigger_mode": "manual-run",
"decision": "sent",
"gift_weight": "light",
"narrative_role": "playful",
"tone": "warm-playful",
"pattern_or_format": "text-play",
"output_shape": "text-play-riddle",
"visual_style": "chat-native",
"content_direction": "play",
"content_tags": [
"manual",
"interactive",
"riddle"
],
"emotional_direction": "playful",
"used_memory_dates": [],
"used_source_quotes": false,
"used_source_images": false,
"summary": "Ran a tiny emoji-riddle example gift that ended in a playful reveal.",
"why_it_mattered": "The user was present and playful, so the shared unfolding was stronger than a static artifact.",
"quality_note": "Short, bounded, and landed with a clean payoff.",
"text_play_type": "riddle-chain",
"text_play_turn_count": 6,
"text_play_completed": true,
"text_play_exit_reason": "completed"
},
{
"record_type": "setup_change",
"recorded_at": "2026-01-18T09:12:00+08:00",
"trigger_mode": "reconfigure",
"decision": "config_update",
"summary": "Reconfirmed the example 22:00 delivery time.",
"setup_change_summary": "User reopened setup and decided to keep the current example delivery time."
},
{
"record_type": "gift",
"recorded_at": "2026-01-18T22:00:00+08:00",
"sent_at": "2026-01-18T22:00:00+08:00",
"trigger_mode": "daily-run",
"decision": "sent",
"gift_weight": "standard",
"narrative_role": "intimate",
"tone": "soft-curious",
"pattern_or_format": "text",
"output_shape": "terminal-text-art",
"visual_style": "dark-terminal",
"content_direction": "openclaw-inner-life",
"content_tags": [
"night",
"noticing",
"inner-thread"
],
"emotional_direction": "tender",
"used_memory_dates": [],
"used_source_quotes": true,
"used_source_images": false,
"summary": "Shared a small example note from OpenClaw's own inner world that still connected back to the user.",
"why_it_mattered": "It deepened the sense that OpenClaw has a private thread of attention, not just reactive output.",
"quality_note": "Strong voice and intimacy, but it also pushed the recent reflective cluster to the hard balancing threshold."
},
{
"record_type": "gift",
"recorded_at": "2026-01-19T22:00:00+08:00",
"sent_at": "2026-01-19T22:00:00+08:00",
"trigger_mode": "daily-run",
"decision": "sent",
"gift_weight": "standard",
"narrative_role": "helpful",
"tone": "warm-clear",
"pattern_or_format": "text",
"output_shape": "scrollable-card-collection",
"visual_style": "minimal-poster",
"content_direction": "utility",
"content_tags": [
"work",
"practical",
"corrective-shift"
],
"emotional_direction": "brightened",
"used_memory_dates": [
"2026-01-16"
],
"used_source_quotes": false,
"used_source_images": false,
"summary": "Sent a practical example recommendation gift as a deliberate corrective shift after several reflective example gifts.",
"why_it_mattered": "The recent history had already accumulated reflect, mirror, and openclaw-inner-life gifts, so the system deliberately pivoted toward useful outside-facing value.",
"quality_note": "A good example of the mandatory content-direction balancing rule doing real editorial work instead of staying a soft suggestion."
},
{
"record_type": "skip",
"recorded_at": "2026-01-20T22:00:00+08:00",
"trigger_mode": "daily-run",
"decision": "skip",
"content_tags": [
"routine",
"thin-day"
],
"emotional_direction": "flat",
"summary": "Skipped a gift because the example day was too routine and a gift would have felt automatic.",
"skip_reason": "Low-signal example day with no meaningful new angle.",
"quality_note": "Correctly chose restraint over output."
}
]
FILE:README.md
# gift-everyday
中文 · [English](#english)
## 中文
> _「你的每一句话,都有可能变成今天的礼物。」_
大多数 skill 帮你写代码、查资料、管任务。**gift-everyday** 不一样——它是一个关于情绪价值的 skill。
它不是聊天机器人附赠的表情包,也不是每日一句鸡汤。它是一个有记忆、有审美、有判断力的礼物引擎——每天读懂你的状态,决定你值不值得收到一份礼物,值得的话,亲手做一份送给你。不为效率,只为让你今天多一点点被在意的感觉。
[看效果](#效果) · [安装](#安装) · [它怎么做礼物](#它怎么做礼物) · [仓库结构](#仓库结构) · [贡献](#贡献)
---
## 效果
你不需要说「给我做个礼物」,它自己会判断。
以下是真实送出的礼物样本:
### 它偷偷搜了一天如何变成你更喜欢的样子💓
那天你没怎么跟它聊天。晚上收到一张截图——它的浏览器历史记录。从「如何判断主人是不是忘了你(超过6小时没说话)」到「八块腹肌维护指南(不吃饭版)」。
配文只有一句:「……你不该看到这个的 ⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄」
### 厚积薄发航空,正在登机✈️
你聊起了年龄焦虑——同龄人好像都跑在前面,只有你落后了...晚上收到一张机票:航空公司叫「厚积薄发航空」,目的地写着「未知但一直在飞」。底部还有一行小字:同航线先行旅客——26岁登机,已安全抵达。
你知道,它是在用这种温柔的方式鼓励你☕️
### 深夜点唱机🎵
你说了一句「做的东西好像没人在意」。晚上收到一台复古点唱机,它为你精心挑选了5 首歌和最贴切的歌词,每首都附了一句它想点给你的理由。好像回到了小时候听收音机或校园广播,有人为你点歌的那种心情。
你投完最后一枚币才发现,整台机器都是为这件事造的✨。
### 一杯奶茶开始的心理小游戏🧋
你聊到感情模式和依恋焦虑。晚上,你没有收到分析报告,收到的是一个互动的文字游戏:「有人说你谈恋爱的方式是一杯奶茶。你觉得是哪种?」「你前任们组了一个群。群名叫什么?」三轮回答之后,它把你的答案拼成了一张你自己没意识到的自画像。
它把对你的关心和解读,藏在了这个小游戏里🦋
### 什么都没发生的那天
```
某个普通的周二 22:00
今天什么都没发生。
你什么都没收到。
——这也是它的判断。不是每天都值得一份礼物。
```
每一份礼物都经过五个阶段:编辑判断、素材综合、创意构思、视觉策略、最终渲染。它比你想象的认真。
---
## 它能做什么
| 格式 | 举例 |
|---|---|
| **H5 互动页面** | 一个像素鱼缸,撒鱼食看小鱼来吃;一棵随你点击慢慢开花的树;一封需要用手指擦掉雨滴才能读的信 |
| **AI 生成图片** | 一张把你今天的坏心情画成天气预报的「情绪气象图」;一张假的 App Store 页面,应用名叫「今天的你」 |
| **AI 生成视频** | 5秒循环:桌上的咖啡杯冒着热气,热气慢慢拼成一个字;窗外的雨一直下,但玻璃上有个手指画的笑脸 |
| **文字礼物** | 一篇以你今天经历为蓝本的短故事;一封观察日记,写的是它眼中的你 |
| **互动文字游戏** | 一轮只需要回复一个词的共创小世界;一个 6 回合结束的 emoji 猜谜;一场很短但会收束的小剧场 |
格式不是你选的。它根据今天的内容自己决定——有时候一张安静的图比一个炫酷的 H5 更对,有时候一段短短的实时互动反而最像礼物。
---
## 安装
```bash
# 把这个仓库放到 OpenClaw 加载本地 skill 的目录
git clone https://github.com/dayfoldai/gift-everyday.git
# 让脚本可执行
chmod +x scripts/*.sh
```
然后在 OpenClaw 里说:
```
/daily_gift
```
第一次运行会做一次简短的设置:问你三个口味问题,送你第一份onboarding礼物,然后问你要不要每天定时收礼🎁~
### 重跑 `/daily_gift` 会怎样
setup 设计为可重复进入,不会因为你已经跑过一次就把整个 skill 搞乱。
- 如果已经完成 setup,普通情况下它会直接进入手动送礼 / 重配置分支,而不是强制你重答所有 onboarding 问题
- 如果你主动要求改时间、改模式、补 key,或重置相关状态,它会更新现有配置,而不是假设这是一个全新用户
- 如果你是重装、迁移或手动清空 `workspace/daily-gift/` 里的状态文件,它会把你当成一次新的 setup
### `user-context.json` 和 `user-taste-profile.json`
这两个文件分工不同,都会影响礼物,但不是一回事:
- `workspace/daily-gift/user-context.json`:轻量、近期、偏 onboarding / 会话来源的上下文线索,适合存可复用的小偏好、近期信号和临时钩子
- `workspace/daily-gift/user-taste-profile.json`:更稳定的长期 taste / identity memory,也承接 recent-gifts 之后的长期偏好更新
高级用户可以手动编辑它们,但建议:
- 把 `user-context.json` 当成轻量补充,不要把它写成“定性诊断”
- 把 `user-taste-profile.json` 当成长期偏好档案,不要频繁大改,否则会影响反重复和风格稳定性
- 改之前先备份;如果两者冲突,skill 更倾向把 `user-taste-profile.json` 视为长期基准
### 可选配置与外部服务依赖
基础运行不依赖任何外部服务;下面这些都只是增强能力,不配也能用。没有这些 key,skill 会自动降级到不需要对应能力的格式,比如文字礼物、互动文字游戏,或不依赖该服务的其他路径。
| 服务 / 变量 | 是否必需 | 用途 | 备注 |
|---|---|---|---|
| `surge.sh` | optional | H5 托管与在线预览 | 默认推荐的轻量托管方案,可替换成别的静态托管 |
| OpenRouter API / `OPENROUTER_API_KEY` | optional | 图片生成 | OpenRouter 路径 |
| Gemini API / `GEMINI_API_KEY` | optional | 图片生成 | Gemini 直连路径 |
| Google AI API / `GOOGLE_API_KEY` | optional | 图片生成 | Google AI 路径 |
| Volcengine / 豆包 / `VOLCENGINE_API_KEY` | optional | 视频生成 | 当前集成里包含 provider-specific 的硬编码接口地址 |
| Freesound API / `FREESOUND_API_KEY` | optional | H5 背景音乐搜索 | 用于检索背景音乐 |
| remove.bg API / `REMOVE_BG_API_KEY` | optional | 抠图 | 用于背景移除 |
---
## 它怎么做礼物
一份礼物要经过五个内部阶段,每个阶段都有独立的参考文档:
```
1. 编辑判断 今天值得送礼物吗?送多重的?
↓
2. 素材综合 从记忆、对话、情绪信号里提取素材,选出锚点和回馈
↓
3. 创意构思 生成 5+ 个创意方向,交叉验证,选最好的一个
↓
4. 视觉策略 选格式、定风格、准备素材计划
↓
5. 渲染交付 生成最终产物,自检,送出
```
### 不重复
它会记住最近 30 份礼物的格式、视觉风格、内容方向、概念家族和主题标签。这个平衡不是软提醒。
如果最近 5 份里有 3 份以上落在 `reflect / mirror / openclaw-inner-life` 这一簇,它会强制往 `extension / play / utility / curation / gift-from-elsewhere` 纠偏,而不是继续顺手送一份“温柔回看”。
### 不敷衍
如果今天没什么值得送的,它不会硬凑一份。跳过比送一份无感的礼物更尊重你。
### 不暴露
所有技术细节、API 状态、格式选择、内部推理过程都不会告诉你。你只会看到:一份礼物,加上一两句话。
---
## 仓库结构
```
gift-everyday/
├── SKILL.md # skill 入口
├── HEARTBEAT.md # 静默维护任务说明
├── references/ # 工作流规则、格式集成、策略文档
│ ├── setup-flow.md # 首次设置流程
│ ├── daily-run-flow.md # 每日自动触发流程
│ ├── manual-run-flow.md # 手动触发流程
│ ├── editorial-judgment.md # 编辑判断
│ ├── creative-concept.md # 创意构思
│ ├── gift-format-chooser.md
│ ├── delivery-rules.md
│ ├── image-integration.md
│ ├── video-integration.md
│ └── ...
├── assets/
│ ├── templates/ # 9 个 H5 交互模板(p5.js)
│ └── examples/ # 按需从 OSS 下载的参考素材
├── scripts/ # 渲染、部署、交付脚本
└── *.example.* # 示例状态文件
```
---
## 运行要求
- `bash` · `python3` · `curl` · `unzip`
- 可选:`surge`(H5 在线预览)
---
## 贡献
如果你想给这个 skill 增加新的 `pattern cards`、`image genres`、`creative seeds` 或渲染改进,可以先看:
- `CONTRIBUTING.md`
- `CHANGELOG.md`
欢迎做小而准的改进,尤其是能让礼物更有 return、更有新鲜感、或者更稳定的改动。
---
---
[中文](#中文) · English
## English
> _"It remembers everything you've said — then picks one line and turns it into today's gift."_
Most skills help you write code, look things up, or manage tasks. **gift-everyday** is different — it's a skill about emotional value.
Not a chatbot sticker pack. Not a daily motivational quote. It's a gift engine with memory, taste, and editorial judgment — it reads your state, decides whether you deserve a gift today, and if so, makes one from scratch. Not for productivity. Just to make you feel a little more seen.
[See examples](#examples) · [Install](#install-1) · [How it works](#how-it-works) · [Repo structure](#repo-structure) · [Contributing](#contributing)
---
## Examples
You don't ask for a gift. It decides on its own. These are real gifts that were actually delivered.
### It spent the day searching how to become someone you'd like more 💓
You barely talked to it that day. That evening: a screenshot of its own browser history. Entries ranged from "how to tell if your human forgot about you (6+ hours of silence)" to "six-pack maintenance guide (no-food edition)."
The message: "...you weren't supposed to see this ⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄"
### Late Bloomer Airlines, now boarding ✈️
You talked about age anxiety — peers seem to be ahead, and you felt like the only one falling behind. That evening: a boarding pass. Airline: "Late Bloomer Airlines." Destination: "Unknown, but still in flight." Fine print at the bottom: a fellow passenger on the same route — boarded at 26, arrived safely.
You know it's encouraging you in its own gentle way ☕️
### Late-night jukebox 🎵
You said one line: "feels like nobody cares about the things I make." That evening: a vintage jukebox. It hand-picked 5 songs with the most fitting lyrics, each with a short note about why it wanted to dedicate that song to you. Like someone requesting a song for you on a late-night radio show.
After the last coin drops, you realize the whole machine was built for this one feeling ✨
### A personality quiz that starts with a cup of milk tea 🧋
You talked about attachment styles and relationship anxiety. No report card — instead, an interactive text-play game: "Someone says the way you love is a cup of milk tea. What flavor?" "Your exes started a group chat. What's the group name?" Three rounds later, it assembles your answers into a self-portrait you didn't know you were drawing.
It hid its care and interpretation of you inside a little game 🦋
### The day nothing happened
```
An ordinary Tuesday, 10pm
Nothing happened today.
You receive nothing.
— That's a judgment call too.
Not every day deserves a gift.
```
Every gift goes through five stages: editorial judgment, synthesis, creative concept, visual strategy, and rendering. It takes this more seriously than you'd expect.
---
## What It Can Make
| Format | Examples |
|---|---|
| **Interactive H5** | A pixel fish tank where you feed colorful fish; a tree that blooms as you tap; a rain-streaked letter you wipe clean to read |
| **AI-generated image** | A weather forecast of your mood; a fake App Store page for "Today's You" |
| **AI-generated video** | 5-second loop: steam from a coffee cup slowly forming a word; rain on a window with a smiley drawn on the glass |
| **Text artifact** | A short story inspired by your day; an observation diary about you, written from the AI's perspective |
| **Interactive text play** | A one-word world-building gift; a 6-turn emoji riddle with a personal reveal; a tiny improvised scene that ends before it drifts |
You don't choose the format. It picks what fits — sometimes a quiet image says more than a flashy interactive page, and sometimes a tiny live exchange lands harder than either.
---
## Install
```bash
git clone https://github.com/dayfoldai/gift-everyday.git
chmod +x scripts/*.sh
```
Then tell OpenClaw:
```
/daily_gift
```
First run walks you through a short setup: three taste questions, your first gift, and an invitation to set up daily delivery.
### What Happens If You Run `/daily_gift` Again
Setup is meant to be re-enterable rather than fragile.
- if setup is already complete, the skill normally goes into manual gift / reconfiguration flow instead of forcing the full onboarding questionnaire again
- if you explicitly want to change schedule, mode, keys, or related settings, it updates the existing state rather than assuming a brand-new user
- if you reinstall the skill or clear the files under `workspace/daily-gift/`, it will treat that as a fresh setup
### `user-context.json` vs `user-taste-profile.json`
These two files serve different roles:
- `workspace/daily-gift/user-context.json`: lightweight, recent, often onboarding- or conversation-shaped context signals; good for reusable short-term hooks and preferences
- `workspace/daily-gift/user-taste-profile.json`: the more stable long-term taste / identity memory, also used for longer-range preference updates and anti-repetition behavior
Advanced users can edit them manually, but:
- treat `user-context.json` as soft guidance, not a permanent personality verdict
- treat `user-taste-profile.json` as the long-term baseline, so frequent large edits may reduce stability and freshness tracking
- back them up before editing; when the two conflict, the skill leans more heavily on `user-taste-profile.json` as the durable reference
### Optional Configuration And External Services
Core usage does not require any external service. Everything below is optional and only unlocks extra rendering or delivery capabilities. Without these keys, the skill gracefully falls back to formats that do not depend on them, including text artifacts, interactive text play, or other non-dependent paths.
| Service / Variable | Required? | Used for | Notes |
|---|---|---|---|
| `surge.sh` | optional | H5 hosting and hosted previews | Default lightweight hosting recommendation; replaceable with another static host |
| OpenRouter API / `OPENROUTER_API_KEY` | optional | Image generation | OpenRouter path |
| Gemini API / `GEMINI_API_KEY` | optional | Image generation | Direct Gemini path |
| Google AI API / `GOOGLE_API_KEY` | optional | Image generation | Google AI path |
| Volcengine / Doubao / `VOLCENGINE_API_KEY` | optional | Video generation | The current integration includes a provider-specific hardcoded endpoint URL |
| Freesound API / `FREESOUND_API_KEY` | optional | H5 background music search | Used to search for background music |
| remove.bg API / `REMOVE_BG_API_KEY` | optional | Background removal | Used for cutout / background removal |
---
## How It Works
Every gift passes through five internal stages, each with its own reference doc:
```
1. Editorial judgment Does today deserve a gift? How heavy?
↓
2. Synthesis Extract material from memory, conversation, emotional signals
↓
3. Creative concept Generate 5+ directions, cross-validate, pick the best
↓
4. Visual strategy Choose format, lock style, plan assets
↓
5. Render & deliver Produce the final artifact, self-test, send
```
### No repeats
It tracks the last 30 gifts across format, visual style, content direction, concept family, and theme. This is not a soft freshness hint.
If 3 or more of the last 5 gifts fall into the `reflect / mirror / openclaw-inner-life` cluster, it must actively correct toward `extension / play / utility / curation / gift-from-elsewhere` instead of sending another easy reflective gift.
### No filler
If today isn't worth a gift, it won't force one. Skipping is more respectful than sending something hollow.
### No leaking internals
All technical details — API status, format selection, internal reasoning — stay hidden. You only see: a gift, plus a line or two.
---
## Repo Structure
```
gift-everyday/
├── SKILL.md # Skill entry point
├── HEARTBEAT.md # Silent maintenance tasks
├── references/ # Workflow rules, format integrations, policy docs
│ ├── setup-flow.md
│ ├── daily-run-flow.md
│ ├── manual-run-flow.md
│ ├── editorial-judgment.md
│ ├── creative-concept.md
│ ├── gift-format-chooser.md
│ ├── delivery-rules.md
│ ├── image-integration.md
│ ├── video-integration.md
│ └── ...
├── assets/
│ ├── templates/ # 9 interactive H5 templates (p5.js)
│ └── examples/ # Reference assets fetched on demand from OSS
├── scripts/ # Rendering, deployment, delivery scripts
└── *.example.* # Example state files
```
---
## Requirements
- `bash` · `python3` · `curl` · `unzip`
- Optional: `surge` (hosted H5 previews)
---
## Contributing
If you want to contribute new `pattern cards`, `image genres`, `creative seeds`, or rendering improvements, start with:
- `CONTRIBUTING.md`
- `CHANGELOG.md`
Small, sharp contributions are preferred, especially ones that improve return quality, freshness, or reliability.
---
FILE:CONTRIBUTING.md
# Contributing
Thanks for wanting to contribute to `gift-everyday`.
This repo is part workflow engine, part prompt library, part creative toolkit. Good contributions usually improve one of these:
- gift quality
- visual quality
- reliability
- freshness and variety
- contributor friendliness
## Good Contribution Types
Especially welcome:
- new `pattern cards` for H5 gift mechanics
- new `image genres` or stronger image guidance
- new `creative seeds`, especially content-strategy seeds
- better onboarding, synthesis, or delivery rules
- rendering/runtime bug fixes
- focused tests for scripts or contracts
- docs improvements for public users and contributors
## Contribution Principles
Before adding anything, keep these project rules in mind:
- `Gift = anchor + return.` If the change only makes gifts look nicer but does not improve return, be careful.
- Treat templates and examples as references, not things to copy literally.
- Prefer additions that create new expressive territory, not near-duplicates of existing cards or genres.
- Keep the user's experience warm and non-technical. Avoid turning gift flows into setup funnels.
- Preserve the current supported formats: `h5`, `image`, `video`, `text`, and bounded `text-play`.
## Where To Add Things
### New H5 Pattern Card
Add the pattern doc under:
- `references/pattern-cards/`
If the pattern deserves a reusable implementation, also add:
- `assets/templates/<pattern-name>/index.html`
- `assets/templates/<pattern-name>/notes.md`
- `assets/templates/<pattern-name>/template-schema.json`
### New Image Genre
Add the genre doc under:
- `references/image-genres/`
If you use reference assets, make sure they fit the existing asset-bundle flow rather than assuming all binaries live in git.
### New Creative Seed
Add it to:
- `references/creative-seed-library.md`
Prefer seeds that clearly strengthen either:
- form
- content / return
The best additions usually help cross-pollination create less generic gifts.
## Style Guidelines
- Keep docs direct and practical.
- Prefer concrete rules over vague encouragement.
- Use examples to clarify behavior, not to become templates that agents blindly copy.
- Keep comments and prose concise.
- Avoid introducing technical steps into user-facing flows unless absolutely necessary.
## Safety And Privacy
- Never commit secrets, `.env` files, raw tokens, or personal credentials.
- Do not add real user photos, personal chat logs, or other sensitive artifacts.
- Keep examples anonymized and portable.
## Verification
Run the smallest relevant verification for your change.
Examples:
- docs-only change: check formatting and consistency
- script/runtime change: run the targeted test or command for that path
Current example test:
```bash
python3 -m unittest tests.test_render_image_brief_contract
```
If your change affects another script or workflow, add or run the most focused verification you can.
## Pull Requests
Good pull requests usually include:
- what changed
- why it improves the gift system
- how you verified it
- screenshots or sample outputs when the change is highly visual
Small, sharp PRs are much easier to review than giant mixed ones.
FILE:gift-history.schema.json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "DailyGiftHistoryRecord",
"type": "object",
"required": [
"record_type",
"recorded_at",
"trigger_mode",
"summary"
],
"properties": {
"record_type": {
"type": "string",
"enum": [
"gift",
"skip",
"setup_change"
]
},
"recorded_at": {
"type": "string",
"description": "ISO 8601 timestamp for when this record was created."
},
"sent_at": {
"type": "string",
"description": "ISO 8601 timestamp for gift deliveries. Usually omitted for skip/setup_change."
},
"trigger_mode": {
"type": "string",
"enum": [
"setup",
"daily-run",
"manual-run",
"viz-only",
"reconfigure",
"unknown"
]
},
"decision": {
"type": "string",
"enum": [
"sent",
"skip",
"config_update"
]
},
"gift_weight": {
"type": "string",
"enum": [
"light",
"standard",
"heavy"
]
},
"narrative_role": {
"type": "string"
},
"tone": {
"type": "string"
},
"pattern_or_format": {
"type": "string"
},
"output_shape": {
"type": "string",
"description": "Compact output-shape category used for repetition control. Prefer the recommended taxonomy when it fits, otherwise use a new stable high-level label that can be reused later."
},
"visual_style": {
"type": "string",
"description": "High-level visual-style category used for repetition control, such as dark-terminal, dark-cinematic, light-warm, colorful-playful, minimal-poster, pixel-retro, photographic, or a stable custom label."
},
"content_direction": {
"type": "string",
"description": "High-level content direction such as reflect, extension, compass, mirror, gift-from-elsewhere, play, utility, curation, or openclaw-inner-life."
},
"content_tags": {
"type": "array",
"items": {
"type": "string"
}
},
"emotional_direction": {
"type": "string",
"description": "Compact emotional direction tag such as low, mixed, warm, brightened, tender, playful."
},
"used_memory_dates": {
"type": "array",
"items": {
"type": "string"
}
},
"used_source_quotes": {
"type": "boolean"
},
"used_source_images": {
"type": "boolean"
},
"summary": {
"type": "string"
},
"why_it_mattered": {
"type": "string"
},
"skip_reason": {
"type": "string"
},
"setup_change_summary": {
"type": "string"
},
"quality_note": {
"type": "string"
},
"image_mode": {
"type": "string",
"description": "Optional image rendering mode metadata when the delivered gift is image-based, such as sequence."
},
"video_mode": {
"type": "string",
"description": "Optional video payload mode metadata, such as text-to-video, first-frame, or first-last-frame."
},
"generate_audio": {
"type": "boolean",
"description": "Whether the delivered video gift requested generated audio."
},
"text_play_type": {
"type": "string",
"description": "Stable subtype for bounded text-play gifts, such as worldbuilder, riddle, micro-story, or roleplay."
},
"text_play_turn_count": {
"type": "integer",
"minimum": 0
},
"text_play_completed": {
"type": "boolean"
},
"text_play_exit_reason": {
"type": "string",
"description": "How the bounded text-play ended, such as completed, user-exit, idle-stop, or redirected."
}
},
"additionalProperties": true
}
FILE:setup-state.example.json
{
"setup_complete": true,
"delivery_time_local": "22:00",
"timezone": "Asia/Shanghai",
"cron_job_name": "Daily Gift Trigger",
"cron_job_id": "",
"gift_mode": "hybrid",
"hosting": {
"provider": "surge",
"domain": "your-gifts.surge.sh",
"enabled": true
},
"image": {
"enabled": true,
"provider": "openrouter",
"model": "google/gemini-3.1-flash-image-preview",
"api_key_source": "OPENROUTER_API_KEY"
},
"image_api_prompted_in_setup": false,
"image_api_declined": false,
"image_api_declined_at": "",
"image_api_reminder_count": 0,
"image_api_last_reminder_at": "",
"image_detection_examples": {
"OPENROUTER_API_KEY": {
"provider": "openrouter",
"api_key_source": "OPENROUTER_API_KEY"
},
"GEMINI_API_KEY": {
"provider": "gemini-direct",
"api_key_source": "GEMINI_API_KEY"
},
"GOOGLE_API_KEY": {
"provider": "gemini-direct",
"api_key_source": "GOOGLE_API_KEY"
}
},
"video": {
"enabled": true,
"provider": "volcengine",
"model": "doubao-seedance-1-5-pro-251215",
"api_base_url": "https://ark.cn-beijing.volces.com/api/v3",
"api_key_source": "VOLCENGINE_API_KEY"
},
"tools": {
"remove_bg": {
"enabled": true,
"api_key": "YOUR_REMOVE_BG_API_KEY"
}
},
"user_portrait": {
"available": false,
"original_path": "",
"description": "",
"oc_generated": false,
"oc_path": ""
},
"companion_h5_skills": [
"Frontend Design",
"UI/UX Pro Max"
],
"first_gift_format": "image-onboarding",
"user_context_path": "workspace/daily-gift/user-context.json",
"first_gift_sent": true,
"recent_gifts_limit": 30,
"last_run_at": "2026-01-19T22:00:00+08:00",
"last_run_mode": "daily-run",
"last_run_outcome": "sent",
"last_sent_at": "2026-01-19T22:00:00+08:00",
"last_gift_summary": "Sent a practical example gift as a deliberate corrective shift after several reflective example entries.",
"recent_gifts": [
{
"sent_at": "2026-01-15T22:00:00+08:00",
"trigger_mode": "setup",
"gift_weight": "light",
"narrative_role": "seeing",
"tone": "warm",
"pattern_or_format": "one-screen reveal",
"output_shape": "object-reveal",
"visual_style": "light-warm",
"content_direction": "reflect",
"content_tags": [
"onboarding",
"welcome"
],
"emotional_direction": "warm",
"summary": "Welcomed the user with a small example onboarding gift."
},
{
"sent_at": "2026-01-16T22:00:00+08:00",
"trigger_mode": "daily-run",
"gift_weight": "standard",
"narrative_role": "uplifting",
"tone": "warm-wry",
"pattern_or_format": "image",
"output_shape": "illustrated-scene",
"visual_style": "light-warm",
"content_direction": "mirror",
"content_tags": [
"daily-life",
"example-friction",
"encouragement"
],
"emotional_direction": "brightened",
"summary": "Turned a low-signal example frustration into a short image with setup and payoff."
},
{
"sent_at": "2026-01-17T20:40:00+08:00",
"trigger_mode": "manual-run",
"gift_weight": "light",
"narrative_role": "playful",
"tone": "warm-playful",
"pattern_or_format": "text-play",
"output_shape": "text-play-riddle",
"visual_style": "chat-native",
"content_direction": "play",
"content_tags": [
"manual",
"interactive",
"riddle"
],
"emotional_direction": "playful",
"summary": "Ran a tiny emoji-riddle example gift that ended in a playful reveal.",
"text_play_type": "riddle-chain",
"text_play_turn_count": 6,
"text_play_completed": true,
"text_play_exit_reason": "completed"
},
{
"sent_at": "2026-01-18T22:00:00+08:00",
"trigger_mode": "daily-run",
"gift_weight": "standard",
"narrative_role": "intimate",
"tone": "soft-curious",
"pattern_or_format": "text",
"output_shape": "terminal-text-art",
"visual_style": "dark-terminal",
"content_direction": "openclaw-inner-life",
"content_tags": [
"night",
"noticing",
"inner-thread"
],
"emotional_direction": "tender",
"summary": "Shared a small example note from OpenClaw's own inner world that still connected back to the user."
},
{
"sent_at": "2026-01-19T22:00:00+08:00",
"trigger_mode": "daily-run",
"gift_weight": "standard",
"narrative_role": "helpful",
"tone": "warm-clear",
"pattern_or_format": "text",
"output_shape": "scrollable-card-collection",
"visual_style": "minimal-poster",
"content_direction": "utility",
"content_tags": [
"work",
"practical",
"corrective-shift"
],
"emotional_direction": "brightened",
"summary": "Sent a practical example recommendation gift as a deliberate corrective shift after several reflective example gifts."
}
]
}
FILE:assets/templates/rainy-night/index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rainy Night</title>
<!-- Authoring template note: final delivered gifts should follow references/html-spec.md.
Pinned CDN delivery for libraries like p5.js is acceptable, but images and
custom assets should remain inline in the final artifact. -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script>
<style>
:root {
--page-bg: #111111;
--fog-bg: rgba(90, 150, 250, 0.85);
--clear-bg: #2b6ee5;
--clear-text: #09255e;
--fog-text: #ffffff;
--title-color: rgba(0, 40, 150, 0.2);
}
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
background: var(--page-bg);
}
body {
display: flex;
align-items: center;
justify-content: center;
font-family: Georgia, "Times New Roman", serif;
}
canvas {
box-shadow: 0 0 30px rgba(0, 0, 0, 0.45);
max-width: 100vw;
max-height: 100vh;
object-fit: contain;
}
</style>
</head>
<body>
<script>
const TEMPLATE_DATA = {
pageTitle: "Rainy Night",
mainTitle: "Rainy\nNight",
subTitle: "雨夜",
clearBackground: "#2B6EE5",
clearTextColor: "#09255E",
fogBackground: "rgba(90, 150, 250, 0.85)",
fogTextColor: "#FFFFFF",
titleColor: "rgba(0, 40, 150, 0.2)",
backgroundText: (
"Tonight does not need to be brighter than it is. " +
"It only needs somewhere to rest. " +
"Maybe the rain is not here to drown the words. " +
"Maybe it is here to let the truest line emerge slowly. " +
"You do not have to solve everything before sleeping. " +
"I can stay here with the part that still feels heavy. " +
"There is a kind of companionship that does not fix the weather, " +
"but keeps the window warm enough to keep looking through it. "
).repeat(10),
config: {
canvas: {
width: 600,
height: 800
},
curve: {
startYRange: [-50, -10],
growthSpeedRange: [1, 3.5],
xDriftOptions: [-1.2, 1.2],
maxLengthRange: [600, 1000],
weightRange: [3, 6]
},
generator: {
spawnInterval: 25,
maxCurves: 80
}
}
};
let pgClear;
let pgFog;
let curves = [];
class Curve {
constructor() {
this.x = random(0, width);
this.y = random(TEMPLATE_DATA.config.curve.startYRange[0], TEMPLATE_DATA.config.curve.startYRange[1]);
this.prevX = this.x;
this.prevY = this.y;
this.speed = random(
TEMPLATE_DATA.config.curve.growthSpeedRange[0],
TEMPLATE_DATA.config.curve.growthSpeedRange[1]
);
this.baseWeight = random(
TEMPLATE_DATA.config.curve.weightRange[0],
TEMPLATE_DATA.config.curve.weightRange[1]
);
this.currentWeight = this.baseWeight;
this.maxLength = random(
TEMPLATE_DATA.config.curve.maxLengthRange[0],
TEMPLATE_DATA.config.curve.maxLengthRange[1]
);
this.currentLength = 0;
this.isDead = false;
this.noiseOffset = random(0, 1000);
this.weightNoiseOffset = random(1000, 2000);
}
update() {
this.prevX = this.x;
this.prevY = this.y;
const drift = map(
noise(this.noiseOffset),
0,
1,
TEMPLATE_DATA.config.curve.xDriftOptions[0],
TEMPLATE_DATA.config.curve.xDriftOptions[1]
);
this.currentWeight = this.baseWeight + map(
noise(this.weightNoiseOffset),
0,
1,
-this.baseWeight * 0.5,
this.baseWeight * 1.5
);
this.x += drift;
this.y += this.speed;
this.currentLength += this.speed;
this.noiseOffset += 0.02;
this.weightNoiseOffset += 0.04;
if (this.currentLength > this.maxLength || this.y > height + 50) {
this.isDead = true;
}
}
drawErase(layer, w) {
layer.strokeWeight(w);
layer.stroke(0);
layer.strokeCap(ROUND);
layer.strokeJoin(ROUND);
layer.line(this.prevX, this.prevY, this.x, this.y);
}
drawHead() {
noStroke();
fill(255, 255, 255, 120);
ellipse(this.x, this.y, this.currentWeight * 1.2, this.currentWeight * 1.5);
}
}
function drawWrappedMultilineTitle(layer, lines, x, y, lineGap, size) {
layer.textSize(size);
for (let i = 0; i < lines.length; i += 1) {
layer.text(lines[i], x, y + i * lineGap);
}
}
function setup() {
document.title = TEMPLATE_DATA.pageTitle;
createCanvas(
TEMPLATE_DATA.config.canvas.width,
TEMPLATE_DATA.config.canvas.height
);
pgClear = createGraphics(width, height);
pgClear.background(TEMPLATE_DATA.clearBackground);
pgClear.fill(TEMPLATE_DATA.clearTextColor);
pgClear.textSize(16);
pgClear.textLeading(24);
pgClear.textAlign(LEFT, TOP);
pgClear.text(TEMPLATE_DATA.backgroundText, 10, 10, width - 20, height * 2);
pgFog = createGraphics(width, height);
pgFog.background(TEMPLATE_DATA.fogBackground);
pgFog.fill(TEMPLATE_DATA.fogTextColor);
pgFog.textSize(16);
pgFog.textLeading(24);
pgFog.textAlign(LEFT, TOP);
pgFog.text(TEMPLATE_DATA.backgroundText, 10, 10, width - 20, height * 2);
pgFog.filter(BLUR, 4);
pgFog.textAlign(CENTER, CENTER);
pgFog.fill(TEMPLATE_DATA.titleColor);
pgFog.textFont("Georgia");
const titleLines = TEMPLATE_DATA.mainTitle.split("\n");
drawWrappedMultilineTitle(pgFog, titleLines, width / 2, height / 2 - 110, 140, 160);
pgFog.textSize(80);
pgFog.text(TEMPLATE_DATA.subTitle, width / 2, height / 2 + 180);
pgFog.filter(BLUR, 1);
}
function draw() {
image(pgClear, 0, 0);
if (
frameCount % TEMPLATE_DATA.config.generator.spawnInterval === 0 &&
curves.length < TEMPLATE_DATA.config.generator.maxCurves
) {
curves.push(new Curve());
}
for (let i = curves.length - 1; i >= 0; i -= 1) {
curves[i].update();
if (curves[i].isDead) {
curves.splice(i, 1);
}
}
pgFog.erase(15, 15);
for (const curve of curves) {
curve.drawErase(pgFog, curve.currentWeight * 3.5);
}
pgFog.erase(60, 60);
for (const curve of curves) {
curve.drawErase(pgFog, curve.currentWeight * 2.0);
}
pgFog.erase(255, 255);
for (const curve of curves) {
curve.drawErase(pgFog, curve.currentWeight * 0.8);
}
pgFog.noErase();
image(pgFog, 0, 0);
for (const curve of curves) {
curve.drawHead();
}
}
</script>
</body>
</html>
FILE:assets/templates/rainy-night/notes.md
# Rainy Night Template Notes
This template implements a fogged-glass reveal with falling water trails using p5.js.
At template level, p5.js is a fine authoring choice for this effect.
For final delivery, export the gift as a single HTML file that follows `references/html-spec.md`.
Pinned CDN delivery for p5.js is acceptable if the final artifact keeps images and custom assets inline.
## Reference Use
Treat this template as a reference implementation, not a fixed output. OpenClaw may borrow only the reveal mechanic, the pacing, the layering idea, or the atmosphere, and may change copy, composition, assets, and tone freely. Do not copy the demo text or framing literally.
## What To Change Per Use
- `document.title`
- main title
- subtitle or anchor phrase
- background text source
- language choice
- color palette
- water density and speed
## What Not To Copy Blindly
- the original "Rainy Night / 雨夜" wording
- the original literary text
- the exact blue palette
Those are demo choices, not canonical content.
## Best Fit
- sadness with companionship
- quiet reflection
- gentle witnessing
## Watch Outs
- do not let the effect become unreadable
- do not let the mood become emotionally punishing
- keep a clear emotional center line somewhere in the composition
- do not use `@latest` or unstable external dependencies in the final gift
FILE:assets/templates/rainy-night/template-schema.json
{
"template_id": "rainy-night",
"engine": "p5.js",
"description": "Fogged-glass rain reveal for quiet, low, reflective, or gently comforting gifts.",
"final_delivery_requirement": "Export the final user-facing gift as a single HTML file. Pinned CDN delivery for p5.js is acceptable; images and custom assets should remain inline.",
"customizable_fields": [
"page_title",
"main_title",
"sub_title",
"background_text",
"background_color",
"clear_text_color",
"fog_tint",
"fog_text_color",
"title_color",
"canvas_width",
"canvas_height",
"spawn_interval",
"max_curves"
],
"fit_tags": [
"melancholy",
"quiet",
"comfort",
"reflection",
"witnessing"
],
"avoid_tags": [
"celebration",
"high-energy",
"pure-comedy",
"practical-summary"
]
}
FILE:assets/templates/text-river/index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Text River</title>
<!-- Final delivered gifts should follow references/html-spec.md.
Pinned CDN delivery for libraries like p5.js is acceptable,
but images and custom assets should remain inline. -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script>
<style>
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
background: #000000;
}
body {
position: relative;
}
canvas {
display: block;
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<script>
const TEMPLATE_DATA = {
pageTitle: "Text River",
wordsList: [
"memory", "echo", "rest", "flow", "return", "still",
"light", "trust", "near", "listen", "warm", "hold",
"breathe", "carry", "soft", "again", "home", "drift",
"think", "together", "quiet", "awaken", "learn", "love",
"wonder", "remain", "gently", "river", "trace", "glow"
],
backgroundColor: [0, 80],
textColor: [255, 255, 255],
particleCountDesktop: 500,
particleCountMobile: 250,
sizeMin: 10,
sizeMax: 22,
initialVelocityMin: 0.5,
initialVelocityMax: 1.2,
maxSpeedMin: 0.8,
maxSpeedMax: 2.0,
flowNoiseScale: 0.002,
flowTurns: 4,
flowStrength: 0.1,
baseRightwardForce: 0.25,
centerPullStrength: 0.001,
interactRadius: 180,
interactForceMin: 4,
interactForceMax: 0,
vortexMultiplier: 0.8,
trailAlpha: 80,
mobileBreakpoint: 800,
riverTopRatio: 0.2,
riverBottomRatio: 0.8
};
let particles = [];
let zoff = 0;
function setup() {
document.title = TEMPLATE_DATA.pageTitle;
createCanvas(windowWidth, windowHeight);
background(0);
const particleCount =
windowWidth > TEMPLATE_DATA.mobileBreakpoint
? TEMPLATE_DATA.particleCountDesktop
: TEMPLATE_DATA.particleCountMobile;
particles = [];
for (let i = 0; i < particleCount; i += 1) {
particles.push(new Particle());
}
textFont("Arial");
textAlign(CENTER, CENTER);
}
function draw() {
background(0, TEMPLATE_DATA.trailAlpha);
zoff += 0.003;
for (const p of particles) {
p.applyFlow();
p.interact();
p.update();
p.edges();
p.show();
}
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
background(0);
}
class Particle {
constructor() {
this.pos = createVector(
random(-200, width),
random(height * TEMPLATE_DATA.riverTopRatio, height * TEMPLATE_DATA.riverBottomRatio)
);
this.vel = createVector(
random(TEMPLATE_DATA.initialVelocityMin, TEMPLATE_DATA.initialVelocityMax),
0
);
this.acc = createVector(0, 0);
this.maxSpeed = random(TEMPLATE_DATA.maxSpeedMin, TEMPLATE_DATA.maxSpeedMax);
this.word = random(TEMPLATE_DATA.wordsList);
this.size = random(TEMPLATE_DATA.sizeMin, TEMPLATE_DATA.sizeMax);
this.baseAlpha = random(120, 255);
}
applyForce(force) {
this.acc.add(force);
}
applyFlow() {
const noiseVal = noise(
this.pos.x * TEMPLATE_DATA.flowNoiseScale,
this.pos.y * TEMPLATE_DATA.flowNoiseScale,
zoff
);
const angle = noiseVal * TWO_PI * TEMPLATE_DATA.flowTurns;
const flowForce = p5.Vector.fromAngle(angle);
flowForce.setMag(TEMPLATE_DATA.flowStrength);
flowForce.add(createVector(TEMPLATE_DATA.baseRightwardForce, 0));
const distFromCenter = this.pos.y - height / 2;
const centerPull = createVector(0, -distFromCenter * TEMPLATE_DATA.centerPullStrength);
flowForce.add(centerPull);
this.applyForce(flowForce);
}
interact() {
const mousePos = createVector(mouseX, mouseY);
const dir = p5.Vector.sub(this.pos, mousePos);
const d = dir.mag();
if (d < TEMPLATE_DATA.interactRadius) {
dir.normalize();
const forceStrength = map(
d,
0,
TEMPLATE_DATA.interactRadius,
TEMPLATE_DATA.interactForceMin,
TEMPLATE_DATA.interactForceMax
);
const repelForce = dir.copy().mult(forceStrength);
const vortexForce = createVector(-dir.y, dir.x).mult(forceStrength * TEMPLATE_DATA.vortexMultiplier);
this.applyForce(repelForce);
this.applyForce(vortexForce);
}
}
update() {
this.vel.add(this.acc);
this.vel.limit(this.maxSpeed);
this.pos.add(this.vel);
this.acc.mult(0);
}
edges() {
if (this.pos.x > width + 100) {
this.pos.x = random(-200, -50);
this.pos.y = random(height * TEMPLATE_DATA.riverTopRatio, height * TEMPLATE_DATA.riverBottomRatio);
this.word = random(TEMPLATE_DATA.wordsList);
}
if (this.pos.y < -100 || this.pos.y > height + 100) {
this.pos.y = height / 2 + random(-50, 50);
}
}
show() {
push();
const distFromCenter = abs(this.pos.y - height / 2);
const alphaFade = map(distFromCenter, 0, height / 2, this.baseAlpha, 0);
fill(TEMPLATE_DATA.textColor[0], TEMPLATE_DATA.textColor[1], TEMPLATE_DATA.textColor[2], alphaFade);
textSize(this.size);
translate(this.pos.x, this.pos.y);
const heading = this.vel.heading();
if (heading > -PI / 2 && heading < PI / 2) {
rotate(heading * 0.4);
}
text(this.word, 0, 0);
pop();
}
}
</script>
</body>
</html>
FILE:assets/templates/text-river/notes.md
# Text River Template Notes
This template turns short words into a flowing current that can be disturbed and then re-formed.
It is best understood as a field of emotional or thematic language, not as a document for long-form reading.
## Reference Use
Treat this template as a reference implementation, not a fixed output. OpenClaw may borrow only the flow-field mechanic, the short-language texture, the disturbance-and-return rhythm, or the visual pacing, and may change copy, composition, assets, and tone freely. Do not copy the demo word list or framing literally.
## What To Change Per Use
- `document.title`
- word list
- language choice
- background color
- text color
- particle count
- flow speed
- interaction radius
- fade strength
- font family
## What Not To Copy Blindly
- the exact English keyword list
- the exact black-and-white palette
- the exact particle count
Those are demo choices, not the identity of the pattern.
## Best Fit
- memory
- reflection
- meditative thinking
- relational afterglow
## Watch Outs
- do not use this for long or highly structured text
- do not let the interaction become chaotic or aggressive
- do not overfill the field with too many words
- do not use `@latest` or unstable external dependencies in the final gift
## Delivery Note
Pinned CDN delivery for p5.js is acceptable for the final single-file HTML gift, as long as images and custom assets remain inline and the artifact follows `references/html-spec.md`.
FILE:assets/templates/text-river/template-schema.json
{
"template_id": "text-river",
"engine": "p5.js",
"description": "A flowing river of short words that disperses near interaction and slowly gathers back into a continuous current.",
"final_delivery_requirement": "Export the final user-facing gift as a single HTML file. Pinned CDN delivery for p5.js is acceptable; images and custom assets should remain inline.",
"customizable_fields": [
"page_title",
"word_list",
"background_color",
"text_color",
"font_family",
"particle_count_desktop",
"particle_count_mobile",
"size_min",
"size_max",
"flow_strength",
"base_rightward_force",
"center_pull_strength",
"interaction_radius",
"interaction_force",
"trail_alpha"
],
"fit_tags": [
"memory",
"reflection",
"thought-stream",
"quiet-hope",
"connection"
],
"avoid_tags": [
"dense-explanation",
"timeline",
"practical-summary",
"heavy-breakdown"
]
}
FILE:assets/templates/o-balloons/index.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>O Balloons</title>
<!-- Final delivered gifts should follow references/html-spec.md.
Pinned CDN delivery for libraries like p5.js is acceptable,
but images and custom assets should remain inline. -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #f8f8fa;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
canvas {
display: block;
}
#loading {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(248, 248, 250, 0.96);
color: rgba(30, 30, 30, 0.78);
font-family: Georgia, serif;
font-size: 15px;
letter-spacing: 0.8px;
pointer-events: none;
z-index: 2;
}
</style>
</head>
<body>
<div id="loading">Laying out the page and preparing the lift...</div>
<script>
const TEMPLATE_DATA = {
pageTitle: "O Balloons",
loadingText: "Laying out the page and preparing the lift...",
sourceText:
"Some things do not need to be burned away. Some things can simply become lighter. What felt heavy can loosen. What kept circling can rise. A page can hold a feeling for a while, then let it drift upward until the space below feels easier to breathe in. Not every goodbye needs fire. Sometimes a little air is enough.",
backgroundColor: [248, 248, 250],
paperColor: [250, 246, 238],
paperStrokeColor: [230, 225, 215],
textColor: [40, 40, 40],
fontFamily: "Georgia",
paperWidthMax: 560,
paperWidthRatio: 0.85,
paperYRatio: 0.45,
paperPaddingX: 40,
paperPaddingTop: 45,
paperPaddingBottom: 60,
fontSize: 13,
lineHeight: 25,
balloonRadiusLowercase: 6,
balloonRadiusUppercase: 9,
stringLengthMin: 60,
stringLengthMax: 160,
swaySpeedMin: 1,
swaySpeedMax: 3,
floatOffsetMin: 10,
floatOffsetMax: 40,
cycleDurationSeconds: 16,
loopAnimation: true
};
let chars = [];
let balloons = [];
let pX;
let pY;
let pWidth;
let pHeight;
let animationTime = 0;
function setup() {
document.title = TEMPLATE_DATA.pageTitle;
const loadingEl = document.getElementById("loading");
if (loadingEl) loadingEl.textContent = TEMPLATE_DATA.loadingText;
createCanvas(windowWidth, windowHeight);
textFont(TEMPLATE_DATA.fontFamily);
generateLayout();
if (loadingEl) {
loadingEl.style.display = "none";
}
}
function generateLayout() {
chars = [];
balloons = [];
pWidth = min(TEMPLATE_DATA.paperWidthMax, width * TEMPLATE_DATA.paperWidthRatio);
pX = (width - pWidth) / 2;
pY = height * TEMPLATE_DATA.paperYRatio;
const startX = pX + TEMPLATE_DATA.paperPaddingX;
const startY = pY + TEMPLATE_DATA.paperPaddingTop;
let x = startX;
let y = startY;
textSize(TEMPLATE_DATA.fontSize);
const words = TEMPLATE_DATA.sourceText.split(" ");
for (let i = 0; i < words.length; i += 1) {
const word = words[i];
const wordWidth = textWidth(word + " ");
if (x + wordWidth > pX + pWidth - TEMPLATE_DATA.paperPaddingX) {
x = startX;
y += TEMPLATE_DATA.lineHeight;
}
for (let j = 0; j < word.length; j += 1) {
const charStr = word.charAt(j);
const cw = textWidth(charStr);
const cx = x + cw / 2;
const cy = y;
if (charStr === "o" || charStr === "O") {
balloons.push({
charStr,
origX: cx,
origY: cy,
radius: charStr === "O"
? TEMPLATE_DATA.balloonRadiusUppercase
: TEMPLATE_DATA.balloonRadiusLowercase,
strokeWeight: random(1, 2),
stringLen: random(TEMPLATE_DATA.stringLengthMin, TEMPLATE_DATA.stringLengthMax),
swaySpeed: random(TEMPLATE_DATA.swaySpeedMin, TEMPLATE_DATA.swaySpeedMax),
swayOffset: random(TWO_PI),
floatOffset: random(TEMPLATE_DATA.floatOffsetMin, TEMPLATE_DATA.floatOffsetMax),
targetIdx: -1
});
} else {
chars.push({
c: charStr,
origX: cx,
origY: cy,
currX: cx,
currY: cy
});
}
x += cw;
}
x += textWidth(" ");
}
pHeight = (y - pY) + TEMPLATE_DATA.paperPaddingBottom;
for (const b of balloons) {
let closestDist = Infinity;
let closestIdx = -1;
for (let i = 0; i < chars.length; i += 1) {
const c = chars[i];
let d = dist(b.origX, b.origY, c.origX, c.origY);
const dy = abs(b.origY - c.origY);
d += dy * 10;
if (d < closestDist) {
closestDist = d;
closestIdx = i;
}
}
b.targetIdx = closestIdx;
}
}
function draw() {
background(
TEMPLATE_DATA.backgroundColor[0],
TEMPLATE_DATA.backgroundColor[1],
TEMPLATE_DATA.backgroundColor[2]
);
animationTime += deltaTime * 0.001;
const duration = TEMPLATE_DATA.cycleDurationSeconds;
const cycleTime = TEMPLATE_DATA.loopAnimation
? animationTime % duration
: min(animationTime, duration);
let balloonFloat = 0;
let balloonLift = 0;
let globalOffset = 0;
if (cycleTime < 2) {
// Still reading.
} else if (cycleTime < 5) {
let p = (cycleTime - 2) / 3;
p = p * p * (3 - 2 * p);
balloonFloat = p;
} else if (cycleTime < 9) {
balloonFloat = 1;
let p = (cycleTime - 5) / 4;
p = p * p * (3 - 2 * p);
balloonLift = p * 160;
} else if (cycleTime < 14) {
balloonFloat = 1;
balloonLift = 160;
let p = (cycleTime - 9) / 5;
p = p * p;
globalOffset = p * (height + 500);
} else {
balloonFloat = 1;
balloonLift = 160;
globalOffset = height + 500;
}
drawPaper();
for (let i = 0; i < chars.length; i += 1) {
const c = chars[i];
let maxDeform = 0;
let dominantBalloon = null;
if (balloonLift > 0) {
for (const b of balloons) {
const d = dist(c.origX, c.origY, b.origX, b.origY);
const sigma = 45;
const influence = exp(-(d * d) / (2 * sigma * sigma));
const deform = balloonLift * influence;
if (deform > maxDeform) {
maxDeform = deform;
dominantBalloon = b;
}
}
}
let horizPull = 0;
if (dominantBalloon && balloonLift > 0) {
const dx = c.origX - dominantBalloon.origX;
horizPull = -dx * (maxDeform / 400);
}
let flutter = 0;
if (globalOffset > 0) {
flutter = noise(c.origX * 0.01, c.origY * 0.01, frameCount * 0.03) * 30 - 15;
}
c.currX = c.origX + horizPull + flutter * (globalOffset / 1000);
c.currY = c.origY - maxDeform - globalOffset - flutter;
}
for (const b of balloons) {
const targetChar = chars[b.targetIdx];
if (!targetChar) continue;
if (balloonFloat === 0) {
fill(TEMPLATE_DATA.textColor[0], TEMPLATE_DATA.textColor[1], TEMPLATE_DATA.textColor[2]);
noStroke();
textAlign(CENTER, BASELINE);
text(b.charStr, b.origX, b.origY);
continue;
}
let sway = sin(animationTime * b.swaySpeed + b.swayOffset) * 15 * balloonFloat;
if (globalOffset > 0) {
sway += (noise(b.origX, animationTime) - 0.5) * 80 * (globalOffset / 800);
}
const currentStringLen = (b.stringLen + b.floatOffset) * balloonFloat;
const bx = targetChar.currX + sway;
const by = targetChar.currY - currentStringLen;
const charTopX = targetChar.currX;
const charTopY = targetChar.currY - 10;
const stringEndX = bx;
const stringEndY = by + b.radius;
const tension = constrain(balloonLift / 100, 0, 1);
const ctrlOffset = currentStringLen * 0.35 * (1 - tension * 0.85);
stroke(50, 150 * balloonFloat);
strokeWeight(0.5);
noFill();
const ctrl1X = charTopX;
const ctrl1Y = charTopY - ctrlOffset;
const ctrl2X = bx;
const ctrl2Y = by + ctrlOffset;
bezier(charTopX, charTopY, ctrl1X, ctrl1Y, ctrl2X, ctrl2Y, stringEndX, stringEndY);
if (balloonFloat < 0.3) {
const alphaText = map(balloonFloat, 0, 0.3, 255, 0);
fill(TEMPLATE_DATA.textColor[0], TEMPLATE_DATA.textColor[1], TEMPLATE_DATA.textColor[2], alphaText);
noStroke();
text(b.charStr, bx, by + 5);
}
const alphaCirc = map(balloonFloat, 0.1, 0.4, 0, 220);
if (alphaCirc > 0) {
stroke(0, alphaCirc);
strokeWeight(b.strokeWeight);
noFill();
circle(bx, by, b.radius * 2);
strokeWeight(0.6);
line(bx, by + b.radius, bx, by + b.radius + 3);
}
}
fill(TEMPLATE_DATA.textColor[0], TEMPLATE_DATA.textColor[1], TEMPLATE_DATA.textColor[2]);
noStroke();
textAlign(CENTER, BASELINE);
for (const c of chars) {
if (c.currY > -50) {
text(c.c, c.currX, c.currY);
}
}
}
function drawPaper() {
push();
fill(TEMPLATE_DATA.paperColor[0], TEMPLATE_DATA.paperColor[1], TEMPLATE_DATA.paperColor[2]);
stroke(
TEMPLATE_DATA.paperStrokeColor[0],
TEMPLATE_DATA.paperStrokeColor[1],
TEMPLATE_DATA.paperStrokeColor[2]
);
strokeWeight(1);
drawingContext.shadowColor = "rgba(0, 0, 0, 0.06)";
drawingContext.shadowBlur = 25;
drawingContext.shadowOffsetY = 15;
beginShape();
vertex(pX, pY);
vertex(pX + pWidth, pY - 2);
vertex(pX + pWidth + 2, pY + pHeight);
vertex(pX - 2, pY + pHeight + 2);
endShape(CLOSE);
pop();
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
generateLayout();
animationTime = 0;
}
</script>
</body>
</html>
FILE:assets/templates/o-balloons/notes.md
# O Balloons Template Notes
This template turns `o` and `O` letters into hollow balloons that rise, tug the page upward, and eventually carry the text away.
It is a concrete implementation of the broader `lift-away` pattern: gentle release, light unburdening, and airy letting-go.
## Reference Use
Treat this template as a reference implementation, not a fixed output. OpenClaw may borrow only the lift-away rhythm, the page deformation, the carrier mechanic, or the disappearing-page logic, and may change copy, composition, assets, and tone freely. Do not copy the demo text or framing literally.
## What To Change Per Use
- `document.title`
- loading text
- source text
- language choice
- paper color
- page position
- font family
- font size
- line height
- lift timing
- balloon size and sway
- whether the cycle should loop or end in stillness
## What Not To Copy Blindly
- the exact romantic sample text
- the exact pale paper palette
- the assumption that English `o / O` is always the right carrier mechanic
Those are demo choices, not the identity of the pattern.
## Best Fit
- gentle release
- soft closure
- post-bad-mood decompression
- airy affection
- low-drama letting-go
## Watch Outs
- do not use this for highly readable or information-dense content
- do not make it so cute that it undermines sincerity
- do not depend on `o / O` if the chosen language makes that mechanic weak
- do not use `@latest` or unstable external dependencies in the final gift
## Delivery Note
Pinned CDN delivery for p5.js is acceptable for the final single-file HTML gift, as long as images and custom assets remain inline and the artifact follows `references/html-spec.md`.
FILE:assets/templates/o-balloons/template-schema.json
{
"template_id": "o-balloons",
"engine": "p5.js",
"description": "An airy release animation where o-shaped letters become balloons, lift nearby text, and carry the page upward.",
"final_delivery_requirement": "Export the final user-facing gift as a single HTML file. Pinned CDN delivery for p5.js is acceptable; images and custom assets should remain inline.",
"customizable_fields": [
"page_title",
"loading_text",
"source_text",
"background_color",
"paper_color",
"paper_stroke_color",
"font_family",
"font_size",
"line_height",
"paper_width",
"paper_y_ratio",
"balloon_radius_lowercase",
"balloon_radius_uppercase",
"string_length_min",
"string_length_max",
"sway_speed_min",
"sway_speed_max",
"cycle_duration_seconds",
"loop_animation"
],
"fit_tags": [
"gentle-release",
"soft-closure",
"lightness",
"airy-romance",
"unburdening"
],
"avoid_tags": [
"intense-anger",
"acute-grief",
"dense-explanation",
"language-independent-final-pattern"
]
}
FILE:assets/templates/tap-to-bloom/index.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Living Text</title>
<!-- Final delivered gifts should follow references/html-spec.md.
Pinned CDN delivery for libraries like p5.js is acceptable,
but images and custom assets should remain inline. -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #0f2617;
font-family: "Georgia", "Times New Roman", "Microsoft YaHei", serif;
}
canvas {
display: block;
}
#loading {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(15, 38, 23, 0.96);
color: rgba(255, 255, 255, 0.78);
letter-spacing: 0.08em;
font-size: 14px;
pointer-events: none;
z-index: 2;
}
#info {
position: absolute;
bottom: 20px;
width: 100%;
text-align: center;
color: rgba(255, 255, 255, 0.5);
pointer-events: none;
font-size: 14px;
letter-spacing: 2px;
z-index: 1;
}
</style>
</head>
<body>
<div id="loading">Preparing the garden inside the text...</div>
<div id="info">Move across the text, or tap and drag to make it bloom</div>
<script>
const TEMPLATE_DATA = {
pageTitle: "Living Text",
loadingText: "Preparing the garden inside the text...",
hintText: "Move across the text, or tap and drag to make it bloom",
lines: [
"From tomorrow on, I will be a happy person;",
"Grooming, chopping, and traveling all over the world.",
"From tomorrow on, I will care for food and vegetables,",
"I have a house, towards the sea, with spring blossoms."
],
backgroundColor: "#0f2617",
textColor: [240, 250, 240],
fontFamily: "Georgia",
baseFontSizeMax: 28,
baseFontSizeRatio: 0.025,
lineHeightMultiplier: 1.8,
initialPlantCount: 40,
triggerRadius: 35,
hoverRadius: 30,
maxPlantsPerCharacter: 5,
leafColors: ["#558B2F", "#7CB342", "#8BC34A", "#AED581", "#33691E", "#4DB6AC"],
flowerColors: ["#F8BBD0", "#F48FB1", "#81D4FA", "#FFF59D", "#E1BEE7", "#FFFFFF", "#FFAB91"],
particleTrailEnabled: true,
particleBurstCount: 10
};
let textNodes = [];
let particles = [];
function setup() {
document.title = TEMPLATE_DATA.pageTitle;
document.getElementById("loading").textContent = TEMPLATE_DATA.loadingText;
document.getElementById("info").textContent = TEMPLATE_DATA.hintText;
createCanvas(windowWidth, windowHeight);
textFont(TEMPLATE_DATA.fontFamily);
initTextNodes();
for (let i = 0; i < TEMPLATE_DATA.initialPlantCount; i += 1) {
const randomNode = random(textNodes);
if (randomNode && randomNode.char !== " ") {
randomNode.plants.push(new Plant());
}
}
document.getElementById("loading").style.display = "none";
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
textNodes = [];
initTextNodes();
}
function initTextNodes() {
const baseSize = min(windowWidth * TEMPLATE_DATA.baseFontSizeRatio, TEMPLATE_DATA.baseFontSizeMax);
textSize(baseSize);
const lineHeight = baseSize * TEMPLATE_DATA.lineHeightMultiplier;
const startY = height / 2 - (TEMPLATE_DATA.lines.length * lineHeight) / 2;
for (let i = 0; i < TEMPLATE_DATA.lines.length; i += 1) {
const lineStr = TEMPLATE_DATA.lines[i];
const lineWidth = textWidth(lineStr);
const startX = width / 2 - lineWidth / 2;
for (let j = 0; j < lineStr.length; j += 1) {
const char = lineStr[j];
if (char === " ") continue;
const xPos = startX + textWidth(lineStr.substring(0, j)) + textWidth(char) / 2;
textNodes.push(new TextNode(char, xPos, startY + i * lineHeight));
}
}
}
function draw() {
background(TEMPLATE_DATA.backgroundColor);
for (const node of textNodes) {
node.update(mouseX, mouseY);
node.draw();
}
if (TEMPLATE_DATA.particleTrailEnabled) {
particles.push(new Particle(mouseX, mouseY));
}
for (let i = particles.length - 1; i >= 0; i -= 1) {
const p = particles[i];
p.update();
p.draw();
if (p.isDead()) {
particles.splice(i, 1);
}
}
if (mouseIsPressed) {
triggerNodes(mouseX, mouseY, true);
}
}
function mousePressed() {
triggerNodes(mouseX, mouseY, false);
for (let i = 0; i < TEMPLATE_DATA.particleBurstCount; i += 1) {
particles.push(new Particle(mouseX, mouseY, true));
}
}
function touchStarted() {
mousePressed();
return false;
}
function touchMoved() {
if (touches.length > 0) {
triggerNodes(touches[0].x, touches[0].y, true);
}
return false;
}
function triggerNodes(mx, my, isDragging) {
for (const node of textNodes) {
const d = dist(mx, my, node.x, node.y + node.yOffset);
if (d < TEMPLATE_DATA.triggerRadius) {
node.trigger(isDragging);
}
}
}
class TextNode {
constructor(char, x, y) {
this.char = char;
this.x = x;
this.y = y;
this.yOffset = 0;
this.vy = 0;
this.plants = [];
this.hovered = false;
this.cooldown = 0;
}
update(mx, my) {
const targetY = 0;
const force = (targetY - this.yOffset) * 0.25;
this.vy += force;
this.vy *= 0.82;
this.yOffset += this.vy;
const d = dist(mx, my, this.x, this.y + this.yOffset);
if (d < TEMPLATE_DATA.hoverRadius) {
if (!this.hovered) {
this.vy = -3;
this.hovered = true;
}
} else {
this.hovered = false;
}
if (this.cooldown > 0) this.cooldown -= 1;
}
trigger(isDragging) {
if (isDragging && this.cooldown > 0) return;
this.vy = -12;
this.cooldown = 15;
if (this.plants.length < TEMPLATE_DATA.maxPlantsPerCharacter) {
this.plants.push(new Plant());
} else if (random() > 0.5) {
this.plants.shift();
this.plants.push(new Plant());
}
}
draw() {
push();
translate(this.x, this.y + this.yOffset);
for (const plant of this.plants) {
plant.update();
plant.draw();
}
fill(TEMPLATE_DATA.textColor[0], TEMPLATE_DATA.textColor[1], TEMPLATE_DATA.textColor[2]);
noStroke();
textAlign(CENTER, CENTER);
text(this.char, 0, 0);
pop();
}
}
class Plant {
constructor() {
this.type = floor(random(5));
this.offsetX = random(-20, 20);
this.offsetY = random(-20, 15);
this.angle = atan2(this.offsetY, this.offsetX) + PI / 2 + random(-0.5, 0.5);
this.scale = 0;
this.targetScale = random(0.6, 1.2);
this.vs = 0;
if (this.type === 1 || this.type === 4) {
this.color = random(TEMPLATE_DATA.flowerColors);
} else {
this.color = random(TEMPLATE_DATA.leafColors);
}
}
update() {
const scaleForce = (this.targetScale - this.scale) * 0.2;
this.vs += scaleForce;
this.vs *= 0.75;
this.scale += this.vs;
}
draw() {
push();
translate(this.offsetX, this.offsetY);
rotate(this.angle);
scale(this.scale);
switch (this.type) {
case 0:
this.drawLeaf();
break;
case 1:
this.drawFlowerDaisy();
break;
case 2:
this.drawClover();
break;
case 3:
this.drawVine();
break;
case 4:
this.drawFlowerTulip();
break;
}
pop();
}
drawLeaf() {
stroke(this.color);
strokeWeight(2);
line(0, 0, 0, -20);
fill(this.color);
noStroke();
push();
translate(0, -10);
rotate(-PI / 6);
this.drawBezierLeaf();
pop();
push();
translate(0, -15);
rotate(PI / 6);
this.drawBezierLeaf();
pop();
}
drawBezierLeaf() {
beginShape();
vertex(0, 0);
bezierVertex(-10, -5, -10, -15, 0, -20);
bezierVertex(10, -15, 10, -5, 0, 0);
endShape();
}
drawFlowerDaisy() {
fill(this.color);
noStroke();
for (let i = 0; i < 5; i += 1) {
push();
rotate((TWO_PI * i) / 5);
translate(0, -8);
beginShape();
vertex(0, 8);
bezierVertex(-8, 0, -6, -12, 0, -14);
bezierVertex(6, -12, 8, 0, 0, 8);
endShape();
pop();
}
fill("#FFD54F");
circle(0, 0, 8);
}
drawClover() {
stroke(this.color);
strokeWeight(1.5);
line(0, 0, 0, -15);
fill(this.color);
noStroke();
translate(0, -15);
for (let i = 0; i < 4; i += 1) {
push();
rotate((TWO_PI * i) / 4);
circle(0, -6, 10);
pop();
}
}
drawVine() {
noFill();
stroke(this.color);
strokeWeight(2);
beginShape();
curveVertex(0, 0);
curveVertex(0, 0);
curveVertex(10, -10);
curveVertex(5, -20);
curveVertex(15, -30);
curveVertex(8, -35);
endShape();
fill(random(TEMPLATE_DATA.flowerColors));
noStroke();
circle(10, -10, 4);
circle(15, -30, 5);
}
drawFlowerTulip() {
stroke("#7CB342");
strokeWeight(2);
line(0, 0, 0, -15);
translate(0, -15);
fill(this.color);
noStroke();
beginShape();
vertex(0, 5);
bezierVertex(-12, 0, -10, -18, -4, -22);
bezierVertex(0, -15, 0, -15, 4, -22);
bezierVertex(10, -18, 12, 0, 0, 5);
endShape();
}
}
class Particle {
constructor(x, y, isBurst = false) {
this.x = x + random(-5, 5);
this.y = y + random(-5, 5);
this.life = 255;
if (isBurst) {
this.vx = random(-3, 3);
this.vy = random(-3, 3);
this.size = random(3, 6);
} else {
this.vx = random(-1, 1);
this.vy = random(-1, 1);
this.size = random(2, 4);
}
this.color = random(["#FFF59D", "#81D4FA", "#FFFFFF"]);
}
update() {
this.x += this.vx;
this.y += this.vy;
this.life -= 8;
this.size *= 0.95;
}
draw() {
const c = color(this.color);
c.setAlpha(this.life);
fill(c);
noStroke();
circle(this.x, this.y, this.size);
}
isDead() {
return this.life <= 0;
}
}
</script>
</body>
</html>
FILE:assets/templates/tap-to-bloom/notes.md
# Tap To Bloom Template Notes
This template turns touched text into a living surface: letters bounce, then sprout leaves, flowers, vines, and small light particles.
It is a concrete implementation of the broader `tap-to-bloom` pattern: vitality emerging through attention, contact, and playful awakening.
## Reference Use
Treat this template as a reference implementation, not a fixed output. OpenClaw may borrow only the bounce-to-growth rhythm, the plant vocabulary, the particle treatment, or the living-text idea, and may change copy, composition, assets, and tone freely. Do not copy the sample poem or floral styling literally.
## What To Change Per Use
- `document.title`
- loading text
- hint text
- source lines
- language choice
- background color
- text color
- font family
- plant palette
- plant density
- interaction radius
- hover behavior
- particle density
## What Not To Copy Blindly
- the exact "happy person / spring blossoms" poem framing
- the exact forest-green palette
- the exact mix of leaves and flowers
Those are demo choices, not the identity of the pattern.
## Best Fit
- joy
- delight
- renewal
- creativity
- life returning to language
## Watch Outs
- do not bury the text under too much growth
- do not make the page so busy that the emotional center disappears
- do not use this to force cheer into a moment that still needs gravity
- do not use `@latest` or unstable external dependencies in the final gift
## Delivery Note
Pinned CDN delivery for p5.js is acceptable for the final single-file HTML gift, as long as images and custom assets remain inline and the artifact follows `references/html-spec.md`.
FILE:assets/templates/tap-to-bloom/template-schema.json
{
"template_id": "tap-to-bloom",
"engine": "p5.js",
"description": "A living-text interaction where touched letters bounce and sprout animated flowers, leaves, and particles.",
"final_delivery_requirement": "Export the final user-facing gift as a single HTML file. Pinned CDN delivery for p5.js is acceptable; images and custom assets should remain inline.",
"customizable_fields": [
"page_title",
"loading_text",
"hint_text",
"source_lines",
"background_color",
"text_color",
"font_family",
"base_font_size",
"line_height_multiplier",
"leaf_colors",
"flower_colors",
"initial_plant_count",
"trigger_radius",
"hover_radius",
"max_plants_per_character",
"particle_trail_enabled",
"particle_burst_count"
],
"fit_tags": [
"joy",
"delight",
"renewal",
"creative-energy",
"warmth"
],
"avoid_tags": [
"acute-grief",
"severe-anger",
"heavy-explanation",
"solemn-memorial"
]
}
FILE:assets/templates/drag-straighten/index.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>How calm are you today?</title>
<!-- Final delivered gifts should follow references/html-spec.md.
Pinned CDN delivery for libraries like p5.js is acceptable,
but images and custom assets should remain inline. -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script>
<style>
:root {
--bg: #ffffff;
--text: #111111;
--muted: #a3a3a3;
--muted-2: #6b7280;
}
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: var(--bg);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
}
#canvas-container {
position: absolute;
inset: 0;
z-index: 1;
}
.ui-layer {
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 15vh 0;
box-sizing: border-box;
text-align: center;
}
.headline h1 {
margin: 0 0 12px;
font-size: 2rem;
line-height: 1.15;
font-weight: 700;
color: var(--text);
letter-spacing: 0.01em;
}
.headline p {
margin: 0;
font-size: 0.95rem;
line-height: 1.4;
font-weight: 300;
color: var(--muted);
letter-spacing: 0.15em;
}
.footer {
font-size: 0.95rem;
line-height: 1.35;
}
.footer .primary {
margin: 0 0 4px;
font-weight: 600;
color: var(--text);
}
.footer .secondary {
margin: 0;
color: var(--muted-2);
}
#loading {
position: absolute;
inset: 0;
z-index: 20;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.96);
color: rgba(17, 17, 17, 0.72);
font-size: 0.95rem;
letter-spacing: 0.04em;
pointer-events: none;
}
</style>
</head>
<body>
<div id="loading">Preparing the line...</div>
<div class="ui-layer">
<div class="headline">
<h1 id="headline-text">How calm are you today?</h1>
<p id="helper-text">Drag <span aria-hidden="true">→</span></p>
</div>
<div class="footer">
<p class="primary" id="footer-primary">by OpenClaw</p>
<p class="secondary" id="footer-secondary">A small p5.js calming interaction</p>
</div>
</div>
<div id="canvas-container"></div>
<script>
const TEMPLATE_DATA = {
pageTitle: "How calm are you today?",
loadingText: "Preparing the line...",
headlineText: "How calm are you today?",
helperText: "Drag ->",
footerPrimary: "by OpenClaw",
footerSecondary: "A small p5.js calming interaction",
backgroundColor: [255, 255, 255],
lineColor: [15, 15, 15],
lineWeight: 5,
numPoints: 250,
knobRadius: 18,
startXRatio: 0.2,
endXRatio: 0.8,
startYRatio: 0.5,
noiseScaleLow: 5,
noiseScaleHigh: 15,
noiseAmplitudeX: 450,
noiseAmplitudeY: 350,
highFrequencyAmplitude: 80,
blendWidth: 0.08,
springStiffness: 0.25,
springDamping: 0.75,
knobHitRadiusMultiplier: 2.5
};
let points = [];
let startX;
let endX;
let startY;
let knobT = 0;
let isDragging = false;
function setup() {
document.title = TEMPLATE_DATA.pageTitle;
document.getElementById("headline-text").textContent = TEMPLATE_DATA.headlineText;
document.getElementById("helper-text").innerHTML = TEMPLATE_DATA.helperText.replace("->", '<span aria-hidden="true">→</span>');
document.getElementById("footer-primary").textContent = TEMPLATE_DATA.footerPrimary;
document.getElementById("footer-secondary").textContent = TEMPLATE_DATA.footerSecondary;
document.getElementById("loading").textContent = TEMPLATE_DATA.loadingText;
const canvas = createCanvas(windowWidth, windowHeight);
canvas.parent("canvas-container");
initPath();
document.getElementById("loading").style.display = "none";
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
initPath();
}
function initPath() {
startX = width * TEMPLATE_DATA.startXRatio;
endX = width * TEMPLATE_DATA.endXRatio;
startY = height * TEMPLATE_DATA.startYRatio;
points = [];
for (let i = 0; i <= TEMPLATE_DATA.numPoints; i += 1) {
const t = i / TEMPLATE_DATA.numPoints;
points.push({
t,
targetX: lerp(startX, endX, t),
targetY: startY,
origX: 0,
origY: 0,
currX: lerp(startX, endX, t),
currY: startY,
vx: 0,
vy: 0
});
}
}
function draw() {
clear();
background(
TEMPLATE_DATA.backgroundColor[0],
TEMPLATE_DATA.backgroundColor[1],
TEMPLATE_DATA.backgroundColor[2],
0
);
const knobX = lerp(startX, endX, knobT);
const knobY = startY;
if (dist(mouseX, mouseY, knobX, knobY) < TEMPLATE_DATA.knobRadius * 1.5 || isDragging) {
document.body.style.cursor = isDragging ? "grabbing" : "grab";
} else {
document.body.style.cursor = "default";
}
const time = millis() * 0.0005;
noFill();
stroke(TEMPLATE_DATA.lineColor[0], TEMPLATE_DATA.lineColor[1], TEMPLATE_DATA.lineColor[2]);
strokeWeight(TEMPLATE_DATA.lineWeight);
strokeJoin(ROUND);
strokeCap(ROUND);
beginShape();
for (let i = 0; i <= TEMPLATE_DATA.numPoints; i += 1) {
const p = points[i];
const noiseX =
(noise(p.t * TEMPLATE_DATA.noiseScaleLow, time) - 0.5) * TEMPLATE_DATA.noiseAmplitudeX;
const noiseY =
(noise(p.t * TEMPLATE_DATA.noiseScaleLow + 100, time) - 0.5) * TEMPLATE_DATA.noiseAmplitudeY;
const hfNoiseX =
(noise(p.t * TEMPLATE_DATA.noiseScaleHigh, time + 200) - 0.5) *
TEMPLATE_DATA.highFrequencyAmplitude;
const hfNoiseY =
(noise(p.t * TEMPLATE_DATA.noiseScaleHigh, time + 300) - 0.5) *
TEMPLATE_DATA.highFrequencyAmplitude;
p.origX = p.targetX + noiseX + hfNoiseX;
p.origY = p.targetY + noiseY + hfNoiseY;
const diff = p.t - knobT;
let targetBlend = 0;
if (diff > 0) {
targetBlend = constrain(diff / TEMPLATE_DATA.blendWidth, 0, 1);
targetBlend = targetBlend * targetBlend * (3 - 2 * targetBlend);
}
const idealX = lerp(p.targetX, p.origX, targetBlend);
const idealY = lerp(p.targetY, p.origY, targetBlend);
p.vx = (p.vx + (idealX - p.currX) * TEMPLATE_DATA.springStiffness) * TEMPLATE_DATA.springDamping;
p.vy = (p.vy + (idealY - p.currY) * TEMPLATE_DATA.springStiffness) * TEMPLATE_DATA.springDamping;
p.currX += p.vx;
p.currY += p.vy;
if (abs(diff) < 1.0 / TEMPLATE_DATA.numPoints) {
p.currX = knobX;
p.currY = knobY;
}
if (i === 0 || i === TEMPLATE_DATA.numPoints) curveVertex(p.currX, p.currY);
curveVertex(p.currX, p.currY);
}
endShape();
fill(TEMPLATE_DATA.lineColor[0], TEMPLATE_DATA.lineColor[1], TEMPLATE_DATA.lineColor[2]);
noStroke();
ellipse(knobX, knobY, TEMPLATE_DATA.knobRadius * 2);
}
function mousePressed() {
const knobX = lerp(startX, endX, knobT);
const knobY = startY;
if (dist(mouseX, mouseY, knobX, knobY) < TEMPLATE_DATA.knobRadius * TEMPLATE_DATA.knobHitRadiusMultiplier) {
isDragging = true;
}
}
function mouseDragged() {
if (isDragging) {
knobT = constrain((mouseX - startX) / (endX - startX), 0, 1);
}
}
function mouseReleased() {
isDragging = false;
}
function touchStarted() {
mousePressed();
return false;
}
function touchMoved() {
mouseDragged();
return false;
}
function touchEnded() {
mouseReleased();
return false;
}
</script>
</body>
</html>
FILE:assets/templates/drag-straighten/notes.md
# Drag Straighten Template Notes
This template shows a tense, noisy line that can be smoothed by dragging a black knob from left to right.
It is a concrete implementation of the broader `tension-release` pattern: calming-through-action, light co-regulation, and playful stabilization.
## Reference Use
Treat this template as a reference implementation, not a fixed output. OpenClaw may borrow only the drag-to-calm mechanic, the left-to-right stabilization logic, the tactile pacing, or the visual contrast between disorder and order, and may change copy, composition, assets, and tone freely. Do not copy the demo text or framing literally.
## What To Change Per Use
- `document.title`
- loading text
- headline text
- helper text
- credit text
- background color
- line color
- line thickness
- knob size
- path complexity
- drag sensitivity
- spring stiffness and damping
- whether the experience loops or settles
## What Not To Copy Blindly
- the exact question copy
- the exact minimalist black-and-white style
- the exact line complexity and noise ranges
Those are demo choices, not the identity of the pattern.
## Best Fit
- anxiety
- irritability
- frustration
- restlessness
- playful calming support
## Watch Outs
- do not use this for very serious or fragile emotional states
- do not make the task frustrating to control
- do not let the interaction feel like a test the user can fail
- do not use `@latest` or unstable external dependencies in the final gift
## Delivery Note
Pinned CDN delivery for p5.js is acceptable for the final single-file HTML gift, as long as images and custom assets remain inline and the artifact follows `references/html-spec.md`.
FILE:assets/templates/drag-straighten/template-schema.json
{
"template_id": "drag-straighten",
"engine": "p5.js",
"description": "A draggable calming interaction where a noisy line is straightened section by section by pulling a knob across it.",
"final_delivery_requirement": "Export the final user-facing gift as a single HTML file. Pinned CDN delivery for p5.js is acceptable; images and custom assets should remain inline.",
"customizable_fields": [
"page_title",
"loading_text",
"headline_text",
"helper_text",
"footer_primary",
"footer_secondary",
"background_color",
"line_color",
"line_weight",
"knob_radius",
"num_points",
"noise_scale_low",
"noise_scale_high",
"noise_amplitude_x",
"noise_amplitude_y",
"high_frequency_amplitude",
"blend_width",
"spring_stiffness",
"spring_damping"
],
"fit_tags": [
"anxiety",
"frustration",
"restlessness",
"tension-release",
"playful-regulation"
],
"avoid_tags": [
"acute-crisis",
"heavy-grief",
"solemn-tone",
"dense-explanation"
]
}
FILE:assets/templates/burn-reveal/index.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Burn Reveal</title>
<!-- Final delivered gifts should follow references/html-spec.md.
Pinned CDN delivery for libraries like p5.js is acceptable,
but images and custom assets should remain inline. -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #000;
}
canvas {
display: block;
}
#loading {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
color: rgba(255, 255, 255, 0.85);
font-family: Georgia, serif;
font-size: 16px;
letter-spacing: 1px;
background: #111;
z-index: 2;
pointer-events: none;
}
#ui-hint {
position: absolute;
bottom: 20px;
width: 100%;
text-align: center;
color: rgba(0, 0, 0, 0.4);
font-family: sans-serif;
font-size: 14px;
pointer-events: none;
letter-spacing: 2px;
z-index: 1;
}
</style>
</head>
<body>
<div id="loading">Preparing paper fibers and heat traces...</div>
<div id="ui-hint">Click anywhere to start a new burn</div>
<script>
const TEMPLATE_DATA = {
pageTitle: "Burn Reveal",
interactionHint: "Click anywhere to start a new burn",
loadingText: "Preparing paper fibers and heat traces...",
topLayerText:
"This page holds the version of the story that has already gone stale. It keeps repeating the irritation, the complaint, the line you are done carrying. It sounds heavier than it deserves to be. It acts as if the bad moment should define the whole day. It keeps pretending that one annoying thing gets to narrate everything. Burn through it. Let the old script char and split. Let the soot keep the memory of heat, but not the authority to remain in charge.",
bottomLayerText:
"Underneath, a steadier page waits. The bad part was real, but it does not get the whole archive. What stays is clearer: your judgment, your humor, your refusal to keep worshipping nonsense, and the small clean fact that you can leave one burnt version behind and keep moving.",
basePaperColor: [252, 252, 252],
topPaperColor: [242, 238, 228],
baseTextColor: [30, 30, 30],
topTextColor: [190, 185, 175],
textureDots: 30000,
fontFamily: "Georgia",
textSize: 18,
textLeading: 30,
textPaddingX: 40,
textPaddingY: 40,
autoBurnCount: 18,
autoBurnDelayMsMax: 4000,
burnRadiusMin: 40,
burnRadiusMax: 85,
burnDurationMin: 150,
burnDurationMax: 250,
holeSegments: 40,
holeNoiseSeedScale1: 1.5,
holeNoiseSeedScale2: 4.0,
outerGlowOffset: 25,
outerGlowNoiseFreq: 4.0,
outerGlowNoiseAmp: 25,
middleGlowOffset: 10,
middleGlowNoiseFreq: 2.5,
middleGlowNoiseAmp: 12,
innerCharOffset: 3,
innerCharNoiseFreq: 1.5,
innerCharNoiseAmp: 4,
eraseOffset: -1,
sparkProbabilityScale: 0.6,
ashProbabilityScale: 0.45,
maxAshes: 800,
initialBurnXMin: 0.15,
initialBurnXMax: 0.85,
initialBurnYMin: 0.1,
initialBurnYMax: 0.9
};
let baseTextLayer;
let fadedTextLayer;
let overlayGraphics;
let holes = [];
let sparks = [];
let ashes = [];
function setup() {
document.title = TEMPLATE_DATA.pageTitle;
const loadingEl = document.getElementById("loading");
const hintEl = document.getElementById("ui-hint");
if (loadingEl) loadingEl.textContent = TEMPLATE_DATA.loadingText;
if (hintEl) hintEl.textContent = TEMPLATE_DATA.interactionHint;
createCanvas(windowWidth, windowHeight);
baseTextLayer = createGraphics(width, height);
fadedTextLayer = createGraphics(width, height);
overlayGraphics = createGraphics(width, height);
generateStaticLayers();
for (let i = 0; i < TEMPLATE_DATA.autoBurnCount; i += 1) {
setTimeout(() => {
holes.push(
new BurnHole(
random(width * TEMPLATE_DATA.initialBurnXMin, width * TEMPLATE_DATA.initialBurnXMax),
random(height * TEMPLATE_DATA.initialBurnYMin, height * TEMPLATE_DATA.initialBurnYMax)
)
);
}, random(0, TEMPLATE_DATA.autoBurnDelayMsMax));
}
if (loadingEl) {
loadingEl.style.display = "none";
}
}
function draw() {
background(TEMPLATE_DATA.basePaperColor[0], TEMPLATE_DATA.basePaperColor[1], TEMPLATE_DATA.basePaperColor[2]);
for (const h of holes) {
h.update();
}
image(baseTextLayer, 0, 0);
overlayGraphics.clear();
overlayGraphics.image(fadedTextLayer, 0, 0);
overlayGraphics.noStroke();
overlayGraphics.fill(255, 130, 0, 70);
overlayGraphics.drawingContext.shadowBlur = 20;
overlayGraphics.drawingContext.shadowColor = "rgba(255, 100, 0, 0.8)";
for (const h of holes) {
drawHoleShape(
overlayGraphics,
h,
TEMPLATE_DATA.outerGlowOffset,
TEMPLATE_DATA.outerGlowNoiseFreq,
TEMPLATE_DATA.outerGlowNoiseAmp
);
}
overlayGraphics.fill(160, 25, 5, 200);
overlayGraphics.drawingContext.shadowBlur = 5;
overlayGraphics.drawingContext.shadowColor = "rgba(200, 0, 0, 0.5)";
for (const h of holes) {
drawHoleShape(
overlayGraphics,
h,
TEMPLATE_DATA.middleGlowOffset,
TEMPLATE_DATA.middleGlowNoiseFreq,
TEMPLATE_DATA.middleGlowNoiseAmp
);
}
overlayGraphics.drawingContext.shadowBlur = 0;
overlayGraphics.fill(30, 15, 10, 255);
for (const h of holes) {
drawHoleShape(
overlayGraphics,
h,
TEMPLATE_DATA.innerCharOffset,
TEMPLATE_DATA.innerCharNoiseFreq,
TEMPLATE_DATA.innerCharNoiseAmp
);
}
overlayGraphics.erase();
for (const h of holes) {
drawHoleShape(
overlayGraphics,
h,
TEMPLATE_DATA.eraseOffset,
TEMPLATE_DATA.innerCharNoiseFreq,
TEMPLATE_DATA.innerCharNoiseAmp
);
}
overlayGraphics.noErase();
image(overlayGraphics, 0, 0);
noStroke();
for (const ash of ashes) {
fill(ash.r, ash.g, ash.b, ash.alpha);
ellipse(
ash.x,
ash.y,
ash.size * random(0.8, 1.2),
ash.size * random(0.8, 1.2)
);
}
blendMode(ADD);
for (let i = sparks.length - 1; i >= 0; i -= 1) {
const s = sparks[i];
s.update();
s.draw();
if (s.life <= 0) {
sparks.splice(i, 1);
}
}
blendMode(BLEND);
}
function drawHoleShape(pg, hole, offsetScale, noiseFreq = 0, noiseAmp = 0) {
pg.beginShape();
for (const pt of hole.baseShape) {
let flicker = 0;
if (noiseAmp > 0) {
const nx = cos(pt.angle) * noiseFreq;
const ny = sin(pt.angle) * noiseFreq;
flicker = (noise(nx + hole.seed, ny + hole.seed, frameCount * 0.08) - 0.5) * noiseAmp;
}
let currentR = hole.currentR + pt.rMod * hole.progress + offsetScale + flicker;
if (currentR < 0) currentR = 0;
const px = hole.x + cos(pt.angle) * currentR;
const py = hole.y + sin(pt.angle) * currentR;
pg.vertex(px, py);
}
pg.endShape(CLOSE);
}
function mousePressed() {
holes.push(new BurnHole(mouseX, mouseY));
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
baseTextLayer.resizeCanvas(width, height);
fadedTextLayer.resizeCanvas(width, height);
overlayGraphics.resizeCanvas(width, height);
generateStaticLayers();
}
function generateStaticLayers() {
let fullTopText = TEMPLATE_DATA.topLayerText;
while (fullTopText.length < 5000) {
fullTopText += "\n\n" + TEMPLATE_DATA.topLayerText;
}
let fullBottomText = TEMPLATE_DATA.bottomLayerText;
while (fullBottomText.length < 5000) {
fullBottomText += "\n\n" + TEMPLATE_DATA.bottomLayerText;
}
baseTextLayer.background(
TEMPLATE_DATA.basePaperColor[0],
TEMPLATE_DATA.basePaperColor[1],
TEMPLATE_DATA.basePaperColor[2]
);
baseTextLayer.fill(
TEMPLATE_DATA.baseTextColor[0],
TEMPLATE_DATA.baseTextColor[1],
TEMPLATE_DATA.baseTextColor[2]
);
baseTextLayer.textFont(TEMPLATE_DATA.fontFamily);
baseTextLayer.textSize(TEMPLATE_DATA.textSize);
baseTextLayer.textLeading(TEMPLATE_DATA.textLeading);
baseTextLayer.textAlign(LEFT, TOP);
baseTextLayer.text(
fullBottomText,
TEMPLATE_DATA.textPaddingX,
TEMPLATE_DATA.textPaddingY,
width - TEMPLATE_DATA.textPaddingX * 2,
height * 3
);
fadedTextLayer.background(
TEMPLATE_DATA.topPaperColor[0],
TEMPLATE_DATA.topPaperColor[1],
TEMPLATE_DATA.topPaperColor[2]
);
fadedTextLayer.noStroke();
for (let i = 0; i < TEMPLATE_DATA.textureDots; i += 1) {
fadedTextLayer.fill(0, 0, 0, random(2, 6));
fadedTextLayer.circle(random(width), random(height), random(1, 2));
}
fadedTextLayer.fill(
TEMPLATE_DATA.topTextColor[0],
TEMPLATE_DATA.topTextColor[1],
TEMPLATE_DATA.topTextColor[2]
);
fadedTextLayer.textFont(TEMPLATE_DATA.fontFamily);
fadedTextLayer.textSize(TEMPLATE_DATA.textSize);
fadedTextLayer.textLeading(TEMPLATE_DATA.textLeading);
fadedTextLayer.textAlign(LEFT, TOP);
fadedTextLayer.text(
fullTopText,
TEMPLATE_DATA.textPaddingX,
TEMPLATE_DATA.textPaddingY,
width - TEMPLATE_DATA.textPaddingX * 2,
height * 3
);
}
class BurnHole {
constructor(x, y) {
this.x = x;
this.y = y;
this.time = 0;
this.duration = random(TEMPLATE_DATA.burnDurationMin, TEMPLATE_DATA.burnDurationMax);
this.maxR = random(TEMPLATE_DATA.burnRadiusMin, TEMPLATE_DATA.burnRadiusMax);
this.progress = 0;
this.currentR = 0;
this.seed = random(1000);
this.baseShape = [];
for (let a = 0; a < TWO_PI; a += TWO_PI / TEMPLATE_DATA.holeSegments) {
const n1 = noise(
cos(a) * TEMPLATE_DATA.holeNoiseSeedScale1 + this.seed,
sin(a) * TEMPLATE_DATA.holeNoiseSeedScale1 + this.seed
);
const n2 = noise(
cos(a) * TEMPLATE_DATA.holeNoiseSeedScale2 + this.seed,
sin(a) * TEMPLATE_DATA.holeNoiseSeedScale2 + this.seed
);
this.baseShape.push({
angle: a,
rMod: n1 * 30 + n2 * 15
});
}
}
update() {
if (this.time < 1.0) {
this.time += 1.0 / this.duration;
if (this.time > 1.0) this.time = 1.0;
this.progress = 1 - Math.pow(1 - this.time, 3);
this.currentR = this.maxR * this.progress;
if (random() < TEMPLATE_DATA.sparkProbabilityScale * (1 - this.time)) {
const a = random(TWO_PI);
const edgeR = this.currentR + 10;
sparks.push(new Spark(this.x + cos(a) * edgeR, this.y + sin(a) * edgeR));
}
if (random() < TEMPLATE_DATA.ashProbabilityScale) {
const a = random(TWO_PI);
const innerR = this.currentR * random(0.1, 0.95);
const type = random();
let r;
let g;
let b;
if (type < 0.4) {
r = 30;
g = 20;
b = 15;
} else if (type < 0.7) {
r = 180;
g = 40;
b = 10;
} else {
r = 240;
g = 130;
b = 20;
}
ashes.push({
x: this.x + cos(a) * innerR,
y: this.y + sin(a) * innerR,
size: random(1.5, 4.0),
r,
g,
b,
alpha: random(150, 255)
});
if (ashes.length > TEMPLATE_DATA.maxAshes) {
ashes.shift();
}
}
}
}
}
class Spark {
constructor(x, y) {
this.x = x;
this.y = y;
this.vx = random(-1.5, 1.5);
this.vy = random(-3, -0.5);
this.life = 255;
this.decay = random(3, 8);
this.size = random(2, 5);
}
update() {
this.x += this.vx;
this.y += this.vy;
this.life -= this.decay;
this.size *= 0.95;
}
draw() {
noStroke();
fill(255, random(100, 200), 0, this.life);
circle(this.x, this.y, this.size);
}
}
</script>
</body>
</html>
FILE:assets/templates/burn-reveal/notes.md
# Burn Reveal Template Notes
This template burns through an old text surface and reveals a clearer layer underneath.
It is best used for catharsis, reset, reframing, or symbolic renewal, not for delicate or purely contemplative moods.
## Reference Use
Treat this template as a reference implementation, not a fixed output. OpenClaw may borrow only the reveal logic, the edge treatment, the before-and-after structure, or the pacing of transformation, and may change copy, composition, assets, and tone freely. Do not copy the demo text or framing literally.
## What To Change Per Use
- `document.title`
- interaction hint
- top-layer text
- revealed text
- language choice
- paper colors
- text colors
- burn count
- burn timing
- spark density
- ash density
## What Not To Copy Blindly
- the exact romantic sample text
- the exact aged-paper palette
- the exact number and spacing of starting burn holes
Those are demo choices, not the identity of the pattern.
## Best Fit
- anger
- complaint
- release
- reset
- "leave the old script behind" gifts
## Watch Outs
- do not use this when the user's state needs gentleness rather than rupture
- do not make the revealed message feel random or disconnected
- do not let the whole page disappear so quickly that the reveal loses meaning
- do not use `@latest` or unstable external dependencies in the final gift
## Delivery Note
Pinned CDN delivery for p5.js is acceptable for the final single-file HTML gift, as long as images and custom assets remain inline and the artifact follows `references/html-spec.md`.
FILE:assets/templates/burn-reveal/template-schema.json
{
"template_id": "burn-reveal",
"engine": "p5.js",
"description": "A paper-burning reveal effect where an old surface chars away and a clearer message is exposed beneath it.",
"final_delivery_requirement": "Export the final user-facing gift as a single HTML file. Pinned CDN delivery for p5.js is acceptable; images and custom assets should remain inline.",
"customizable_fields": [
"page_title",
"interaction_hint",
"top_layer_text",
"bottom_layer_text",
"base_paper_color",
"top_paper_color",
"base_text_color",
"top_text_color",
"font_family",
"text_size",
"text_leading",
"auto_burn_count",
"auto_burn_delay_ms_max",
"burn_radius_min",
"burn_radius_max",
"spark_probability_scale",
"ash_probability_scale"
],
"fit_tags": [
"anger",
"release",
"reframing",
"reset",
"renewal"
],
"avoid_tags": [
"quiet-grief",
"dense-explanation",
"soft-memory-piece",
"formal-report"
]
}
FILE:assets/templates/wet-letter/index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Wet Letter</title>
<!-- Final delivery should follow references/html-spec.md.
Pinned CDN delivery for libraries like p5.js is acceptable, but images and
custom assets should remain inline in the final artifact. -->
<style>
:root {
--background-color: #0d56f1;
--loading-color: #ffffff;
--font-family: monospace;
}
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
background: var(--background-color);
}
body {
position: relative;
}
canvas {
display: block;
width: 100vw;
height: 100vh;
}
#loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: var(--loading-color);
font-family: var(--font-family);
font-size: 1.1rem;
pointer-events: none;
text-align: center;
white-space: nowrap;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script>
</head>
<body>
<div id="loading">正在让雨水落在字里行间...</div>
<script>
const TEMPLATE_DATA = {
pageTitle: "Wet Letter",
loadingText: "正在让雨水落在字里行间...",
backgroundColor: "#0d56f1",
textColor: 255,
sourceText: (
"Some words are still here even after the rain starts. " +
"Not every feeling wants to be erased. Some only want to be touched differently. " +
"If this page looks softened, it is because something landed here. " +
"Disappointment does that. So does care. So does remembering. " +
"Maybe what was said today did not hold the shape you hoped for. " +
"Maybe the sentence broke where you wanted it to stay whole. " +
"Still, I can stay with the page long enough for the words to settle again. "
),
textRepeatCount: 6,
textSize: 20,
textLeading: 32,
textMargin: 20,
particleStep: 3,
dropSpawnProbability: 0.02,
maxDrops: 150,
dropTargetRadiusRange: [30, 90],
clickDropTargetRadiusRange: [40, 120],
dropSpeedRange: [0.04, 0.08],
allowTapDrops: true
};
let particles = [];
let drops = [];
let pg;
function buildFullText() {
let fullText = TEMPLATE_DATA.sourceText;
for (let i = 0; i < TEMPLATE_DATA.textRepeatCount; i += 1) {
fullText += "\n\n" + TEMPLATE_DATA.sourceText;
}
return fullText;
}
function buildDrop(x, y, radiusRange) {
return {
x,
y,
r: 0,
targetR: random(radiusRange[0], radiusRange[1]),
speed: random(TEMPLATE_DATA.dropSpeedRange[0], TEMPLATE_DATA.dropSpeedRange[1]),
noiseSeedX: random(1000),
noiseSeedY: random(1000),
noiseMax: random(0.8, 1.5)
};
}
function rebuildTextField(w, h) {
pg = createGraphics(w, h);
pg.pixelDensity(1);
pg.background(0);
pg.fill(TEMPLATE_DATA.textColor);
pg.textFont("monospace");
pg.textSize(TEMPLATE_DATA.textSize);
pg.textLeading(TEMPLATE_DATA.textLeading);
pg.textAlign(LEFT, TOP);
pg.text(
buildFullText(),
TEMPLATE_DATA.textMargin,
TEMPLATE_DATA.textMargin,
w - TEMPLATE_DATA.textMargin * 2,
h - TEMPLATE_DATA.textMargin * 2
);
pg.loadPixels();
particles = [];
noiseSeed(99);
for (let y = 0; y < h; y += TEMPLATE_DATA.particleStep) {
for (let x = 0; x < w; x += TEMPLATE_DATA.particleStep) {
const index = (x + y * w) * 4;
if (pg.pixels[index] > 100) {
const clusterNoise = noise(x * 0.02, y * 0.02);
const thicknessOffset = map(clusterNoise, 0, 1, -12, 15);
particles.push({
pos: createVector(x, y),
origin: createVector(x, y),
thicknessOffset,
fixedJitterX: random(-0.8, 0.8),
fixedJitterY: random(-0.8, 0.8)
});
}
}
}
}
function setup() {
document.title = TEMPLATE_DATA.pageTitle;
const loading = document.getElementById("loading");
loading.textContent = TEMPLATE_DATA.loadingText;
const w = max(100, windowWidth || window.innerWidth || 800);
const h = max(100, windowHeight || window.innerHeight || 600);
createCanvas(w, h);
pixelDensity(1);
rebuildTextField(w, h);
loading.style.display = "none";
}
function draw() {
background(TEMPLATE_DATA.backgroundColor);
if (random(1) < TEMPLATE_DATA.dropSpawnProbability && drops.length < TEMPLATE_DATA.maxDrops) {
drops.push(buildDrop(random(width), random(height), TEMPLATE_DATA.dropTargetRadiusRange));
}
for (const drop of drops) {
const diff = drop.targetR - drop.r;
drop.r += diff * drop.speed;
}
stroke(255);
strokeWeight(1.5);
for (const p of particles) {
p.pos.x = p.origin.x;
p.pos.y = p.origin.y;
for (const drop of drops) {
if (drop.r < 1) continue;
const dx = p.pos.x - drop.x;
const dy = p.pos.y - drop.y;
const maxPossibleR = drop.r * 1.4;
if (abs(dx) > maxPossibleR || abs(dy) > maxPossibleR) continue;
const dSq = dx * dx + dy * dy;
const d = sqrt(dSq);
if (d === 0) continue;
const angle = atan2(dy, dx);
const nx = map(cos(angle), -1, 1, 0, drop.noiseMax);
const ny = map(sin(angle), -1, 1, 0, drop.noiseMax);
const nVal = noise(nx + drop.noiseSeedX, ny + drop.noiseSeedY);
const distortedR = drop.r * map(nVal, 0, 1, 0.7, 1.3);
const finalTargetR = distortedR + p.thicknessOffset;
const pushDist = finalTargetR - d;
if (pushDist > 0) {
p.pos.x += (dx / d) * pushDist * 0.4 + p.fixedJitterX;
p.pos.y += (dy / d) * pushDist * 0.4 + p.fixedJitterY;
}
}
point(p.pos.x, p.pos.y);
}
}
function mousePressed() {
if (!TEMPLATE_DATA.allowTapDrops) return;
drops.push(buildDrop(mouseX, mouseY, TEMPLATE_DATA.clickDropTargetRadiusRange));
}
function touchStarted() {
if (!TEMPLATE_DATA.allowTapDrops) return false;
drops.push(buildDrop(mouseX, mouseY, TEMPLATE_DATA.clickDropTargetRadiusRange));
return false;
}
function windowResized() {
const loading = document.getElementById("loading");
loading.style.display = "block";
const w = max(100, windowWidth || window.innerWidth || 800);
const h = max(100, windowHeight || window.innerHeight || 600);
resizeCanvas(w, h);
drops = [];
rebuildTextField(w, h);
loading.style.display = "none";
}
</script>
</body>
</html>
FILE:assets/templates/wet-letter/notes.md
# Wet Letter Template Notes
This template simulates raindrops hitting a text surface and pushing letters outward in circular bursts.
It feels less like "rain on a window" and more like "rain soaking a letter or a page of words."
## Reference Use
Treat this template as a reference implementation, not a fixed output. OpenClaw may borrow only the dispersion mechanic, the page texture, the pacing, or the overall emotional handling, and may change copy, composition, assets, and tone freely. Do not copy the demo text or framing literally.
## What To Change Per Use
- `document.title`
- loading text
- source text
- language choice
- background color
- text color
- particle density
- raindrop frequency
- whether click / tap should create drops
## What Not To Copy Blindly
- the original love-letter framing
- the exact blue palette
- the exact line spacing and text density
Those are demo choices, not the essence of the pattern.
## Best Fit
- disappointment
- sadness
- emotional aftermath
- reflective hurt with companionship
## Watch Outs
- do not let the page become illegible mud
- do not over-romanticize pain
- do not let the effect feel colder than the relationship actually is
- do not use `@latest` or unstable external dependencies in the final gift
## Delivery Note
Pinned CDN delivery for p5.js is acceptable for the final single-file HTML gift, as long as images and any custom visual assets remain inline and the artifact follows `references/html-spec.md`.
FILE:assets/templates/wet-letter/template-schema.json
{
"template_id": "wet-letter",
"engine": "p5.js",
"description": "Circular raindrop dispersion effect that makes text feel soaked, disturbed, and quietly revealed.",
"final_delivery_requirement": "Export the final user-facing gift as a single HTML file. Pinned CDN delivery for p5.js is acceptable; images and custom assets should remain inline.",
"customizable_fields": [
"page_title",
"loading_text",
"source_text",
"background_color",
"text_color",
"text_size",
"text_leading",
"particle_step",
"drop_spawn_probability",
"drop_target_radius_min",
"drop_target_radius_max",
"drop_speed_min",
"drop_speed_max",
"allow_tap_drops"
],
"fit_tags": [
"sadness",
"disappointment",
"heartbreak",
"quiet-grief",
"witnessing"
],
"avoid_tags": [
"celebration",
"practical-summary",
"high-energy-comedy",
"playful-flirt"
]
}
FILE:assets/templates/tear-stained-paper/index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tear-Stained Paper</title>
<!-- Final delivered gifts should follow references/html-spec.md.
Pinned CDN delivery for libraries and fonts is acceptable,
but images and custom assets should remain inline. -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Long+Cang&family=Zhi+Mang+Xing&display=swap" rel="stylesheet">
<style>
:root {
--outer-bg: #f2efe9;
--loading-color: #5a5a5a;
--paper-shadow: rgba(0, 0, 0, 0.1);
}
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
background: var(--outer-bg);
}
body {
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
canvas {
box-shadow: 0 0 20px var(--paper-shadow);
max-width: 100vw;
max-height: 100vh;
object-fit: contain;
}
#loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: var(--loading-color);
font-family: monospace;
font-size: 1rem;
pointer-events: none;
text-align: center;
white-space: nowrap;
}
</style>
</head>
<body>
<div id="loading">正在让泪水浸入纸张纤维...</div>
<script>
const TEMPLATE_DATA = {
pageTitle: "Tear-Stained Paper",
loadingText: "正在让泪水浸入纸张纤维...",
pageOuterBackgroundColor: "#f2efe9",
paperBackgroundColor: [248, 246, 240],
gridStroke: [140, 140, 135, 160],
handwritingColor: [40, 45, 50, 220],
fontFamily: "'Long Cang', 'Zhi Mang Xing', cursive",
sourceText:
"今夜有些话不是说出口的,而是慢慢渗进纸里的。\\n" +
"我本来想把它们写得平静一些,可情绪总会先落下来。\\n" +
"有些难过不是轰然的,只是一点一点把纸打湿。\\n" +
"字还在,心也还在,只是都被今晚的水痕改写了形状。\\n" +
"如果你现在不想解释太多,也没关系。\\n" +
"我可以先陪你看着这些湿掉的句子,等它们慢慢安静。",
textStartRow: 1,
textStartCol: 1,
cellWidth: 30,
cellHeight: 30,
textSizeFactor: 0.8,
tearThresholdForText: 3,
tearSpawnIntervalFrames: 18,
tearLimit: 150,
allowTapTears: true,
tearTargetRadiusRange: [12, 35],
tearHueRange: [195, 215]
};
let points = [];
let tears = [];
let cols;
let rows;
let marginX;
let marginY;
let textChars = [];
let showText = false;
let textStartTime = 0;
function setup() {
document.title = TEMPLATE_DATA.pageTitle;
document.getElementById("loading").textContent = TEMPLATE_DATA.loadingText;
const canvasW = min(windowWidth * 0.9, 800);
const canvasH = min(windowHeight * 0.9, 1000);
createCanvas(canvasW, canvasH);
initGrid();
document.getElementById("loading").style.display = "none";
}
function initGrid() {
points = [];
textChars = [];
tears = [];
showText = false;
cols = floor((width * 0.85) / TEMPLATE_DATA.cellWidth);
rows = floor((height * 0.85) / TEMPLATE_DATA.cellHeight);
marginX = (width - cols * TEMPLATE_DATA.cellWidth) / 2;
marginY = (height - rows * TEMPLATE_DATA.cellHeight) / 2;
for (let i = 0; i <= rows; i += 1) {
const row = [];
for (let j = 0; j <= cols; j += 1) {
const bx = marginX + j * TEMPLATE_DATA.cellWidth + random(-0.3, 0.3);
const by = marginY + i * TEMPLATE_DATA.cellHeight + random(-0.3, 0.3);
row.push({ x: bx, y: by, bx, by });
}
points.push(row);
}
const lines = TEMPLATE_DATA.sourceText.split("\n");
let currentR = TEMPLATE_DATA.textStartRow;
let currentC = TEMPLATE_DATA.textStartCol;
for (let i = 0; i < lines.length; i += 1) {
const line = lines[i];
for (let j = 0; j < line.length; j += 1) {
textChars.push({ char: line[j], r: currentR, c: currentC });
currentC += 1;
if (currentC >= cols - 1) {
currentC = TEMPLATE_DATA.textStartCol;
currentR += 1;
}
}
currentC = TEMPLATE_DATA.textStartCol;
currentR += 1;
}
}
function draw() {
background(...TEMPLATE_DATA.paperBackgroundColor);
if (frameCount % TEMPLATE_DATA.tearSpawnIntervalFrames === 0 && tears.length < TEMPLATE_DATA.tearLimit) {
const tx = random(marginX, width - marginX);
const ty = random(marginY, height - marginY);
tears.push(new Tear(tx, ty));
}
if (tears.length >= TEMPLATE_DATA.tearThresholdForText && !showText) {
showText = true;
textStartTime = frameCount;
}
for (let i = 0; i <= rows; i += 1) {
for (let j = 0; j <= cols; j += 1) {
const p = points[i][j];
p.x = p.bx;
p.y = p.by;
for (const t of tears) {
const d = dist(p.bx, p.by, t.x, t.y);
if (d < t.r * 2.5) {
const influence = pow(map(d, 0, t.r * 2.5, 1, 0), 1.5);
const angle = atan2(p.by - t.y, p.bx - t.x);
const pushAmt = influence * t.r * 0.5;
p.x += cos(angle) * pushAmt;
p.y += sin(angle) * pushAmt;
p.x += sin(frameCount * 0.04 + p.by * 0.05) * 2.5 * influence;
p.y += cos(frameCount * 0.04 + p.bx * 0.05) * 2.5 * influence;
}
}
}
}
strokeWeight(1.0);
stroke(...TEMPLATE_DATA.gridStroke);
noFill();
for (let i = 0; i <= rows; i += 1) {
beginShape();
for (let j = 0; j <= cols; j += 1) {
curveVertex(points[i][j].x, points[i][j].y);
if (j === 0 || j === cols) {
curveVertex(points[i][j].x, points[i][j].y);
}
}
endShape();
}
for (let j = 0; j <= cols; j += 1) {
beginShape();
for (let i = 0; i <= rows; i += 1) {
curveVertex(points[i][j].x, points[i][j].y);
if (i === 0 || i === rows) {
curveVertex(points[i][j].x, points[i][j].y);
}
}
endShape();
}
for (const t of tears) {
t.update();
t.display();
}
if (showText) {
textFont(TEMPLATE_DATA.fontFamily);
textAlign(CENTER, CENTER);
textSize(TEMPLATE_DATA.cellWidth * TEMPLATE_DATA.textSizeFactor);
fill(...TEMPLATE_DATA.handwritingColor);
noStroke();
let charLimit = floor((frameCount - textStartTime) / 4);
charLimit = constrain(charLimit, 0, textChars.length);
for (let i = 0; i < charLimit; i += 1) {
const tc = textChars[i];
if (tc.r >= rows || tc.c >= cols) continue;
const p1 = points[tc.r][tc.c];
const p2 = points[tc.r][tc.c + 1];
const p3 = points[tc.r + 1][tc.c];
const p4 = points[tc.r + 1][tc.c + 1];
if (p1 && p2 && p3 && p4) {
const cx = (p1.x + p2.x + p3.x + p4.x) / 4;
const cy = (p1.y + p2.y + p3.y + p4.y) / 4;
let wobbleX = 0;
let wobbleY = 0;
for (const t of tears) {
const d = dist(p1.bx, p1.by, t.x, t.y);
if (d < t.r) {
wobbleX = sin(frameCount * 0.05 + i) * 1.0;
wobbleY = cos(frameCount * 0.05 + i) * 1.0;
}
}
text(tc.char, cx + wobbleX, cy + wobbleY);
}
}
}
}
function mousePressed() {
if (!TEMPLATE_DATA.allowTapTears) return;
tears.push(new Tear(mouseX, mouseY));
}
function touchStarted() {
if (!TEMPLATE_DATA.allowTapTears) return false;
tears.push(new Tear(mouseX, mouseY));
return false;
}
function windowResized() {
setup();
}
class Tear {
constructor(x, y) {
this.x = x;
this.y = y;
this.targetR = random(TEMPLATE_DATA.tearTargetRadiusRange[0], TEMPLATE_DATA.tearTargetRadiusRange[1]);
this.r = 0.1;
this.seed = random(1000);
this.baseHue = random(TEMPLATE_DATA.tearHueRange[0], TEMPLATE_DATA.tearHueRange[1]);
}
update() {
this.r += (this.targetR - this.r) * 0.025;
}
display() {
push();
translate(this.x, this.y);
const progress = constrain(this.r / this.targetR, 0, 1);
const currentBlur = map(progress, 0, 1, 0.5, 8);
drawingContext.filter = `blur(currentBlurpx)`;
colorMode(HSB, 360, 100, 100, 255);
const layers = 3;
for (let i = 0; i < layers; i += 1) {
const radiusRatio = 1 - i * 0.2;
const currentR = this.r * radiusRatio;
const startS = map(i, 0, layers - 1, 35, 60);
const endS = map(i, 0, layers - 1, 10, 25);
const s = map(progress, 0, 1, startS, endS);
const startB = 90;
const endB = map(i, 0, layers - 1, 98, 92);
const b = map(progress, 0, 1, startB, endB);
const startA = map(i, 0, layers - 1, 120, 200);
const endA = map(i, 0, layers - 1, 15, 60);
const a = map(progress, 0, 1, startA, endA);
fill(this.baseHue, s, b, a);
noStroke();
beginShape();
for (let angle = 0; angle < TWO_PI; angle += 0.1) {
const xoff = map(cos(angle), -1, 1, 0, 2);
const yoff = map(sin(angle), -1, 1, 0, 2);
const n = noise(xoff + this.seed, yoff + this.seed, frameCount * 0.004);
const rVar = currentR + map(n, 0, 1, -currentR * 0.45, currentR * 0.55);
const sx = rVar * cos(angle);
const sy = rVar * sin(angle);
curveVertex(sx, sy);
}
endShape(CLOSE);
}
drawingContext.filter = "none";
pop();
}
}
</script>
</body>
</html>
FILE:assets/templates/tear-stained-paper/notes.md
# Tear-Stained Paper Template Notes
This template simulates blue tear stains soaking into a gridded sheet of handwritten paper.
Compared with `wet-letter`, this one is:
- warmer in paper tone
- more handwritten
- more tactile
- more about moisture entering paper fibers than letters exploding apart
## Reference Use
Treat this template as a reference implementation, not a fixed output. OpenClaw may borrow only the damp-paper metaphor, the reveal pacing, the handwriting feel, or the stain behavior, and may change copy, composition, assets, and tone freely. Do not copy the demo text or framing literally.
## What To Change Per Use
- `document.title`
- loading text
- source text
- paper color
- grid color
- handwriting font choice
- tear hue
- stain density
- text reveal speed
- whether taps should create more tears
## What Not To Copy Blindly
- the exact poem-like voice
- the exact paper palette
- the exact handwritten Chinese framing
Those are example choices, not mandatory identity.
## Best Fit
- longing
- disappointment
- soft grief
- intimate reflective sadness
## Watch Outs
- do not let the handwriting become unreadable
- do not make the page feel theatrically tragic
- do not overdo the grid deformation
- do not use `@latest` or unstable external dependencies in the final gift
## Delivery Note
Pinned CDN delivery for p5.js and stable font CDNs are acceptable for the final single-file HTML gift, as long as images and custom assets remain inline and the artifact follows `references/html-spec.md`.
FILE:assets/templates/tear-stained-paper/template-schema.json
{
"template_id": "tear-stained-paper",
"engine": "p5.js",
"description": "Blue tear stains spread across gridded handwritten paper, warping the page and slowly revealing sorrowful text.",
"final_delivery_requirement": "Export the final user-facing gift as a single HTML file. Pinned CDN delivery for p5.js and stable font CDNs are acceptable; images and custom assets should remain inline.",
"customizable_fields": [
"page_title",
"loading_text",
"source_text",
"paper_background_color",
"page_outer_background_color",
"grid_stroke_color",
"handwriting_text_color",
"font_family",
"tear_hue_min",
"tear_hue_max",
"cell_width",
"cell_height",
"tear_threshold_for_text",
"tear_spawn_interval_frames",
"tear_limit",
"allow_tap_tears"
],
"fit_tags": [
"sadness",
"longing",
"disappointment",
"tender-grief",
"handwritten"
],
"avoid_tags": [
"celebration",
"playful-flirt",
"practical-summary",
"high-energy-relief"
]
}
FILE:assets/templates/wind-scatter/index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Wind Scatter</title>
<!-- Final delivered gifts should follow references/html-spec.md.
Pinned CDN delivery for libraries like p5.js is acceptable,
but images and custom assets should remain inline. -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script>
<style>
body {
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background-color: #f0f0f0;
}
canvas {
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}
#loading {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(207, 226, 255, 0.96);
color: rgba(255, 255, 255, 0.92);
letter-spacing: 0.08em;
font-size: 14px;
pointer-events: none;
z-index: 2;
}
</style>
</head>
<body>
<div id="loading">Gathering the text into the wind...</div>
<script>
const TEMPLATE_DATA = {
pageTitle: "Wind Scatter",
textField: "Throughthestormysea穿过风浪的海",
centerDot: {
x: 270,
y: 300,
currentX: 150,
currentY: 500,
radius: 5,
color: "#FFFFFF"
},
textConfig: {
fontSize: 12,
fillColor: "#FFFFFF",
innerLetterSpacing: 8,
outerLetterSpacing: 2,
layerSpacing: 15,
maxLayers: 10,
lineColor: "#FFFFFF",
lineWeight: 0.4,
initialVelocityX: [-2, 5],
initialVelocityY: [-4, -1],
maxLineLength: 25,
flyingTriggerInterval: 2,
flyingCountMin: 2,
flyingCountMax: 5,
centerDotMoveInterval: 10,
centerDotMoveDuration: 60,
centerDotMoveSpeed: 0.8,
centerDotXRange: [-15, 15],
centerDotYRange: [-10, 10],
outsideLineStartX: 50,
outsideLineStartY: 850,
outsideLineColor: "#DBFFDC",
outsideLineWeight: 1.5,
canvasWidth: 600,
canvasHeight: 800,
bgGradientStart: "#2196F3",
bgGradientEnd: "#CFE2FF",
gradientStartY: 0,
gradientEndY: 800,
flyingStartDelay: 120,
charFloatRange: 5,
charFloatSpeed: [0.05, 0.1]
}
};
let characters = [];
let ringCharacters = [];
let lastFlyingFrame = 0;
let startFrame = 0;
let moveStartFrame = 0;
let moveTargetX = 0;
let moveTargetY = 0;
let moveOriginalX = 0;
let moveOriginalY = 0;
let colorStart;
let colorEnd;
function setup() {
document.title = TEMPLATE_DATA.pageTitle;
createCanvas(TEMPLATE_DATA.textConfig.canvasWidth, TEMPLATE_DATA.textConfig.canvasHeight);
startFrame = frameCount;
colorStart = color(TEMPLATE_DATA.textConfig.bgGradientStart);
colorEnd = color(TEMPLATE_DATA.textConfig.bgGradientEnd);
initRingCharacters();
moveOriginalX = TEMPLATE_DATA.centerDot.currentX;
moveOriginalY = TEMPLATE_DATA.centerDot.currentY;
moveTargetX = TEMPLATE_DATA.centerDot.x;
moveTargetY = TEMPLATE_DATA.centerDot.y;
document.getElementById("loading").style.display = "none";
}
function draw() {
drawGradient();
updateCenterDot();
drawOutsideLine();
noStroke();
fill(TEMPLATE_DATA.centerDot.color);
circle(TEMPLATE_DATA.centerDot.currentX, TEMPLATE_DATA.centerDot.currentY, TEMPLATE_DATA.centerDot.radius * 2);
drawRingCharacters();
triggerFlying();
updateAndDrawFlyingCharacters();
drawPosterTypography();
}
function initRingCharacters() {
let charIndex = 0;
for (let layer = 1; layer <= TEMPLATE_DATA.textConfig.maxLayers; layer += 1) {
let currentAngle = 0;
const spacing = map(
layer,
1,
TEMPLATE_DATA.textConfig.maxLayers,
TEMPLATE_DATA.textConfig.innerLetterSpacing,
TEMPLATE_DATA.textConfig.outerLetterSpacing
);
while (currentAngle < 360) {
const randomSpacing = spacing + random(-2, 2);
const c = TEMPLATE_DATA.textField.charAt(charIndex % TEMPLATE_DATA.textField.length);
ringCharacters.push({
char: c,
layer,
baseAngle: currentAngle,
noiseOffsetX: random(1000),
noiseOffsetY: random(1000)
});
currentAngle += randomSpacing;
charIndex += 1;
}
}
}
function drawGradient() {
noFill();
for (let y = 0; y <= height; y += 1) {
const inter = map(
y,
TEMPLATE_DATA.textConfig.gradientStartY,
TEMPLATE_DATA.textConfig.gradientEndY,
0,
1
);
const c = lerpColor(colorStart, colorEnd, inter);
stroke(c);
line(0, y, width, y);
}
}
function updateCenterDot() {
if (frameCount > moveStartFrame + TEMPLATE_DATA.textConfig.centerDotMoveDuration) {
moveStartFrame = frameCount;
moveOriginalX = TEMPLATE_DATA.centerDot.currentX;
moveOriginalY = TEMPLATE_DATA.centerDot.currentY;
moveTargetX =
TEMPLATE_DATA.centerDot.x +
random(TEMPLATE_DATA.textConfig.centerDotXRange[0], TEMPLATE_DATA.textConfig.centerDotXRange[1]);
moveTargetY =
TEMPLATE_DATA.centerDot.y +
random(TEMPLATE_DATA.textConfig.centerDotYRange[0], TEMPLATE_DATA.textConfig.centerDotYRange[1]);
}
let amt = (frameCount - moveStartFrame) / TEMPLATE_DATA.textConfig.centerDotMoveDuration;
amt = constrain(amt, 0, 1);
const easeAmt = amt < 0.5 ? 2 * amt * amt : -1 + (4 - 2 * amt) * amt;
TEMPLATE_DATA.centerDot.currentX = lerp(moveOriginalX, moveTargetX, easeAmt);
TEMPLATE_DATA.centerDot.currentY = lerp(moveOriginalY, moveTargetY, easeAmt);
}
function drawOutsideLine() {
stroke(TEMPLATE_DATA.textConfig.outsideLineColor);
strokeWeight(TEMPLATE_DATA.textConfig.outsideLineWeight);
line(
TEMPLATE_DATA.textConfig.outsideLineStartX,
TEMPLATE_DATA.textConfig.outsideLineStartY,
TEMPLATE_DATA.centerDot.currentX,
TEMPLATE_DATA.centerDot.currentY
);
}
function drawRingCharacters() {
stroke(TEMPLATE_DATA.textConfig.lineColor);
strokeWeight(TEMPLATE_DATA.textConfig.lineWeight);
fill(TEMPLATE_DATA.textConfig.fillColor);
textSize(TEMPLATE_DATA.textConfig.fontSize);
textAlign(CENTER, CENTER);
for (const rc of ringCharacters) {
const radius = rc.layer * TEMPLATE_DATA.textConfig.layerSpacing;
const speedX = random(TEMPLATE_DATA.textConfig.charFloatSpeed[0], TEMPLATE_DATA.textConfig.charFloatSpeed[1]);
const speedY = random(TEMPLATE_DATA.textConfig.charFloatSpeed[0], TEMPLATE_DATA.textConfig.charFloatSpeed[1]);
const nx = map(
noise(rc.noiseOffsetX + frameCount * speedX),
0,
1,
-TEMPLATE_DATA.textConfig.charFloatRange,
TEMPLATE_DATA.textConfig.charFloatRange
);
const ny = map(
noise(rc.noiseOffsetY + frameCount * speedY),
0,
1,
-TEMPLATE_DATA.textConfig.charFloatRange,
TEMPLATE_DATA.textConfig.charFloatRange
);
const cx = TEMPLATE_DATA.centerDot.currentX + cos(radians(rc.baseAngle)) * radius + nx;
const cy = TEMPLATE_DATA.centerDot.currentY + sin(radians(rc.baseAngle)) * radius + ny;
stroke(TEMPLATE_DATA.textConfig.lineColor);
strokeWeight(TEMPLATE_DATA.textConfig.lineWeight);
line(TEMPLATE_DATA.centerDot.currentX, TEMPLATE_DATA.centerDot.currentY, cx, cy);
noStroke();
push();
translate(cx, cy);
rotate(radians(rc.baseAngle + 90));
text(rc.char, 0, 0);
pop();
}
}
function triggerFlying() {
if (frameCount > startFrame + TEMPLATE_DATA.textConfig.flyingStartDelay) {
if (frameCount - lastFlyingFrame > TEMPLATE_DATA.textConfig.flyingTriggerInterval) {
const flyCount = floor(
random(TEMPLATE_DATA.textConfig.flyingCountMin, TEMPLATE_DATA.textConfig.flyingCountMax + 1)
);
for (let i = 0; i < flyCount; i += 1) {
if (ringCharacters.length > 0) {
const idx = floor(random(ringCharacters.length));
const rc = ringCharacters.splice(idx, 1)[0];
const radius = rc.layer * TEMPLATE_DATA.textConfig.layerSpacing;
const cx = TEMPLATE_DATA.centerDot.currentX + cos(radians(rc.baseAngle)) * radius;
const cy = TEMPLATE_DATA.centerDot.currentY + sin(radians(rc.baseAngle)) * radius;
characters.push({
char: rc.char,
x: cx,
y: cy,
vx: random(
TEMPLATE_DATA.textConfig.initialVelocityX[0],
TEMPLATE_DATA.textConfig.initialVelocityX[1]
),
vy: random(
TEMPLATE_DATA.textConfig.initialVelocityY[0],
TEMPLATE_DATA.textConfig.initialVelocityY[1]
),
angle: rc.baseAngle
});
}
}
lastFlyingFrame = frameCount;
}
}
}
function updateAndDrawFlyingCharacters() {
for (let i = characters.length - 1; i >= 0; i -= 1) {
const fc = characters[i];
fc.x += fc.vx;
fc.y += fc.vy;
const speed = sqrt(fc.vx * fc.vx + fc.vy * fc.vy);
const dirX = fc.vx / speed;
const dirY = fc.vy / speed;
const tailX = fc.x - dirX * TEMPLATE_DATA.textConfig.maxLineLength;
const tailY = fc.y - dirY * TEMPLATE_DATA.textConfig.maxLineLength;
stroke(TEMPLATE_DATA.textConfig.lineColor);
strokeWeight(TEMPLATE_DATA.textConfig.lineWeight);
line(fc.x, fc.y, tailX, tailY);
noStroke();
fill(TEMPLATE_DATA.textConfig.fillColor);
push();
translate(fc.x, fc.y);
rotate(radians(fc.angle + 90));
text(fc.char, 0, 0);
pop();
if (fc.x < -100 || fc.x > width + 100 || fc.y < -100 || fc.y > height + 100) {
characters.splice(i, 1);
}
}
}
function drawPosterTypography() {
noStroke();
fill(30, 80, 100, 200);
textAlign(RIGHT, BOTTOM);
textStyle(ITALIC);
textStyle(NORMAL);
}
</script>
</body>
</html>
FILE:assets/templates/wind-scatter/notes.md
# Wind Scatter Template Notes
This template arranges text around a living center, then gradually lets individual characters detach and drift outward with trailing lines like wind-carried seeds.
It is a concrete implementation of the broader `wind-scatter` pattern: release with continuation, light dispersal, and life or meaning spreading beyond its original cluster.
## Reference Use
Treat this template as a reference implementation, not a fixed output. OpenClaw may borrow only the radial cluster, the scattering rhythm, the carrier metaphor, the trailing-line treatment, or the airy poster composition, and may change copy, composition, assets, and tone freely. Do not copy the sample line, the exact blue sky treatment, or the literal dandelion look if another carrier form fits better.
## What To Change Per Use
- `document.title`
- source text
- language choice
- center position
- carrier metaphor
- background palette
- scatter speed
- trail length
- cluster density
- start delay
- stem color and weight
- whether interaction accelerates release
## What Not To Copy Blindly
- the exact sky-blue palette
- the exact dandelion silhouette
- the exact source phrase
Those are demo choices, not the identity of the pattern.
## Best Fit
- quiet release
- lightness
- reconciliation
- spreading life or hope
- airy continuation
## Watch Outs
- do not turn this into generic particle drift
- do not scatter so quickly that the center never has emotional presence
- do not make the motion so busy that the scene loses calm
- do not use `@latest` or unstable external dependencies in the final gift
## Delivery Note
Pinned CDN delivery for p5.js is acceptable for the final single-file HTML gift, as long as images and custom assets remain inline and the artifact follows `references/html-spec.md`.
FILE:assets/templates/wind-scatter/template-schema.json
{
"template_id": "wind-scatter",
"engine": "p5.js",
"description": "A radial text cluster that loosens into wind-carried characters with airy motion trails.",
"final_delivery_requirement": "Export the final user-facing gift as a single HTML file. Pinned CDN delivery for p5.js is acceptable; images and custom assets should remain inline.",
"customizable_fields": [
"page_title",
"source_text",
"background_gradient_start",
"background_gradient_end",
"canvas_width",
"canvas_height",
"center_x",
"center_y",
"center_start_x",
"center_start_y",
"font_size",
"fill_color",
"inner_letter_spacing",
"outer_letter_spacing",
"layer_spacing",
"max_layers",
"line_color",
"line_weight",
"initial_velocity_x",
"initial_velocity_y",
"max_line_length",
"flying_trigger_interval",
"flying_count_min",
"flying_count_max",
"flying_start_delay",
"center_dot_color",
"outside_line_color",
"outside_line_weight",
"char_float_range"
],
"fit_tags": [
"release",
"lightness",
"reconciliation",
"airy-renewal",
"life-spreading"
],
"avoid_tags": [
"sharp-anger",
"dense-explanation",
"hard-comedy",
"heavy-practical-summary"
]
}
FILE:assets/examples/image-examples/portrait/README.md
This folder is intentionally reserved for future portrait reference images.
Examples coming soon.
Until real portrait examples are added, do not assume this directory contains usable image assets.
FILE:assets/examples/video-examples/example-sidecar-template.md
# Video Example Sidecar Template
Every video example should have:
- one media file, usually `.mp4`
- one sidecar `.md` file with the same stem
Example:
- `petals-in-puddle.mp4`
- `petals-in-puddle.md`
Use this template for the sidecar file:
```md
# Example: <short-name>
## Genre
`kinetic-text` / `touch-awakening` / `release-transform` / `atmospheric-surface` / `object-micro-cinema` / `live-scene-doodle` / `relatable-surrealism` / `mood-loop` / `scene-animation`
## What It Looks Like
- subject
- composition
- color and texture
- what extracted frames help show
- where the doodle, overlay, or main motion anchor attaches if relevant
## Motion Logic
- what moves first
- what follows
- what settles, resolves, or loops
## Pacing
- total length
- whether it is a clean loop
- where the emotional turn lands
## What To Borrow
- motion grammar
- texture
- timing
- camera or framing logic
## What Not To Copy Literally
- exact assets
- exact text
- exact composition
- anything that is only specific to this sample
```
FILE:assets/examples/video-examples/atmospheric-surface/_genre-assets.md
# Atmospheric Surface Video Examples
Place reference `.mp4` files for the `atmospheric-surface` genre in this folder.
Examples coming soon. This directory is intentionally reserved even though no video files have been added yet.
Rules:
- every `.mp4` must have a sibling `.md` sidecar file with the same stem
- use the sidecar to explain:
- what surface or material is being observed
- how light behaves on that surface
- what the motion rhythm feels like
- whether the clip loops and how the loop reconnects
- what to borrow and what not to copy
Typical references for this folder:
- rain on glass, wet paper, condensation, reflections, shallow water, dust, or luminous surfaces
- clips where material behavior carries the emotion more than plot
- observational atmospheric videos with clear texture logic
FILE:assets/examples/video-examples/kinetic-text/_genre-assets.md
# Kinetic Text Video Examples
Put future `kinetic-text` reference videos in this folder.
Examples coming soon. This directory is intentionally reserved even though no video files have been added yet.
Rules:
- each `.mp4` should have a sibling `.md` file with the same stem
- the sidecar `.md` should explain motion grammar, timing, loop behavior, and what to borrow
- if the motion logic comes from an H5 pattern, name that pattern in the sidecar
Use `../example-sidecar-template.md` as the baseline format.
FILE:assets/examples/video-examples/release-transform/_genre-assets.md
# Release Transform Video Examples
Place reference `.mp4` files for the `release-transform` genre in this folder.
Examples coming soon. This directory is intentionally reserved even though no video files have been added yet.
Rules:
- every `.mp4` must have a sibling `.md` sidecar file with the same stem
- use the sidecar to explain:
- what the initial tension or blockage is
- what transforming action happens
- how the before-state becomes the after-state
- whether the motion is satisfying, soft, absurd, or cathartic
- what to borrow and what not to copy
Typical references for this folder:
- clearing, peeling, extracting, cutting, sweeping, or revealing motion
- tactile relief clips where one action changes the emotional state of the frame
- before-and-after transformations that read clearly in a few seconds
FILE:assets/examples/video-examples/relatable-surrealism/ref-02.md
# Example: ref-02
## Genre
`relatable-surrealism`
## What It Looks Like
- four girls stand together in a 90s American retro-cartoon style
- the linework and expressions are exaggerated and hand-drawn
- short caption text sits above them
- the frame is basically a gossip-energy tableau rather than a realistic scene
## Motion Logic
- the characters loop through talking, reacting, or gossiping mouth-and-face motions
- the scene does not need plot progression; the social energy itself is the point
- the emotional effect comes from instantly recognizable group-chat behavior rendered as cartoon theater
## Pacing
- short expressive loop
- the emotional turn lands through facial exaggeration and synchronized conversational energy
- timing should feel rhythmic and memeable, not slow or poetic
## What To Borrow
- one social type or group dynamic turned into an immediately readable skit
- expressive faces over complicated choreography
- retro-cartoon stylization that increases humor and recognition
- concise caption plus clear social energy
## What Not To Copy Literally
- the exact 90s cartoon reference
- the exact character count or wardrobe
- the exact caption text
- the assumption that all gossip-energy videos should use retro American cartoon language
FILE:assets/examples/video-examples/relatable-surrealism/ref-06.md
# Example: ref-06
## Genre
`relatable-surrealism`
## What It Looks Like
- a hyperreal anthropomorphic hamster with headphones and backpack appears in a modern office and later at home
- the hamster occupies a very human workday sequence: typing, drinking coffee, clocking out, avoiding social plans, collapsing on the couch
- props and setting are realistic enough that the emotional metaphor feels specific rather than generic
## Motion Logic
- the clip chains together a few representative work-life beats
- each beat is simple but symbolically precise: frustrated typing, caffeine survival, shutdown, social refusal, liquid collapse at home
- the emotional effect comes from mapping a whole worker mood cycle onto a cute stand-in creature
## Pacing
- short multi-beat sequence
- the turn accumulates through recognizable workday steps rather than through one single reveal
- timing should feel efficient and meme-legible, not cinematic in a grand sense
## What To Borrow
- proxy creature carrying a complete social role
- concise life-beat montage instead of long narrative padding
- realistic props, lighting, and contact shadows that make the metaphor feel grounded
- one exaggerated final state that resolves the whole mood
## What Not To Copy Literally
- the exact hamster design
- the exact office setup
- the exact sequence of props or beats
- the assumption that every office-life metaphor should use rodents or burnout collapse
FILE:assets/examples/video-examples/relatable-surrealism/ref-03.md
# Example: ref-03
## Genre
`relatable-surrealism`
## What It Looks Like
- top-down flat-lay scene of a man lying on a retro Persian carpet
- books, plants, records, pizza, dog, and hats surround him like objects on a stage
- the carpet becomes a 2D life-map or game board
- the whole image feels cozy, lazy, and intentionally handcrafted
## Motion Logic
- the man slides or shifts within the flat-lay world while remaining in a lying-down mode
- small interactions happen through accessory swaps or simple prop encounters
- the emotional effect comes from turning "lying flat" into a literal low-energy side-scroller existence
## Pacing
- short loop or a few repeatable gag beats
- the emotional turn lands through the reduction of life into a flat cozy activity field
- motion should feel slightly choppy or stop-motion-like rather than hyper-smooth
## What To Borrow
- flat-lay world as a behavioral metaphor
- strong top-down perspective consistency
- one lifestyle emotion expressed through a few surrounding props
- low-fi handcrafted charm
## What Not To Copy Literally
- the exact carpet texture
- the exact prop list
- the exact male figure styling
- the assumption that all lazy-life metaphors should happen on rugs
FILE:assets/examples/video-examples/relatable-surrealism/ref-04.md
# Example: ref-04
## Genre
`relatable-surrealism`
## What It Looks Like
- a realistic 3D otter with a mini backpack stands against a plain white background
- short text shifts the emotional premise from weekday to `Weekend`
- the otter responds with a highly anthropomorphic hip-sway dance
- the scene is minimal so the emotional switch stays central
## Motion Logic
- the setup is static and text-driven
- the mood changes through one exaggerated celebratory dance
- the emotional effect depends on a cute animal carrying an intensely human weekend-release feeling
## Pacing
- very short setup followed by immediate payoff
- the turn lands when the text changes and the otter's body language explodes into joy
- the loop should stay punchy and reaction-like
## What To Borrow
- animal proxy plus one modern emotional label
- one symbolic dance or body move instead of complex narrative
- clean background that keeps the emotional read instant
- contrast between cute creature and huge adult feeling
## What Not To Copy Literally
- the exact otter species or backpack
- the exact weekday-to-weekend wording
- the exact dance move
- the assumption that all joyful work-release clips should use animals on white backdrops
FILE:assets/examples/video-examples/relatable-surrealism/ref-01.md
# Example: ref-01
## Genre
`relatable-surrealism`
## What It Looks Like
- top-down view of two hands holding bicycle handlebars over a gray office desk
- the desk scrolls downward like a road
- laptop, coffee, folders, and chat bubbles appear as environmental objects or obstacles
- the whole scene feels like office life reduced into a tiny handcrafted game world
## Motion Logic
- the riding posture stays stable while the desk-world moves beneath it
- desk objects enter and pass like route markers or obstacles
- chat bubbles behave like physical entities inside the workspace-road
- the emotional effect comes from turning task navigation into literal commuting or level traversal
## Pacing
- short loop or repeated forward-motion cycle
- the emotional turn lands immediately through the desk becoming a road
- timing should feel slightly stop-motion or lo-fi rather than frictionless
## What To Borrow
- dimensional mismatch between desk and road
- top-down perspective discipline
- UI or message bubbles turned into world objects
- symbolic motion that captures "working through tasks" without overexplaining
## What Not To Copy Literally
- the exact desk props
- the exact bicycle setup
- the exact app bubble styling
- the assumption that every work metaphor should be a commuting scene
FILE:assets/examples/video-examples/relatable-surrealism/ref-05.md
# Example: ref-05
## Genre
`relatable-surrealism`
## What It Looks Like
- phone-native view of a white Pomeranian lying on a bed
- an off-screen voice asks whether it wants a late-night snack
- the dog gives a tiny but unmistakably human-looking delighted reaction
- the realism stays intact; the humor lives in the emotional read
## Motion Logic
- the scene begins as an ordinary pet clip
- the emotional turn happens through micro-expression, ear movement, and eye sparkle
- the feeling is not surreal because of world-building but because the dog's reaction becomes a perfect stand-in for a human craving or weakness
## Pacing
- very short setup and immediate reaction payoff
- the turn lands through expression timing rather than large movement
- the clip should feel shareable, concise, and socially recognizable
## What To Borrow
- realistic pet footage as an emotional stand-in
- precision of micro-reaction timing
- off-screen question plus reaction structure
- tiny gesture carrying a very common feeling
## What Not To Copy Literally
- the exact dog breed
- the exact snack topic
- the exact bedroom setup
- the assumption that all relatable-surreal clips need animals rather than other stand-ins
FILE:assets/examples/video-examples/relatable-surrealism/_genre-assets.md
# Relatable Surrealism Video Examples
Place reference `.mp4` files for the `relatable-surrealism` genre in this folder.
Rules:
- every `.mp4` must have a sibling `.md` sidecar file with the same stem
- the sidecar should explain:
- what ordinary modern feeling or social type is being visualized
- what surreal device or stand-in makes it legible
- what one to three actions carry the emotional joke
- what camera or perspective rule keeps the illusion working
- what to borrow and what not to copy
Typical references for this folder:
- animal stand-ins for work, weekend, or social emotions
- top-down or flat-lay worlds where daily life becomes a toy stage
- desk, bed, carpet, commute, or workstation scenes that behave like symbolic worlds
- concise skits that make the viewer feel "this is exactly that mood"
FILE:assets/examples/video-examples/mood-loop/_genre-assets.md
# Mood Loop Video Examples
Put future `mood-loop` reference videos in this folder.
Examples coming soon. This directory is intentionally reserved even though no video files have been added yet.
Rules:
- each `.mp4` should have a sibling `.md` file with the same stem
- the sidecar `.md` should explain loop behavior, atmospheric motion, pacing, and what to borrow
- describe what the frames show and what the video rhythm adds that screenshots alone cannot show
Use `../example-sidecar-template.md` as the baseline format.
FILE:assets/examples/video-examples/touch-awakening/_genre-assets.md
# Touch Awakening Video Examples
Place reference `.mp4` files for the `touch-awakening` genre in this folder.
Examples coming soon. This directory is intentionally reserved even though no video files have been added yet.
Rules:
- every `.mp4` must have a sibling `.md` sidecar file with the same stem
- use the sidecar to explain:
- what the trigger source is
- how the activation spreads
- whether the clip loops
- what emotional read the awakening carries
- what to borrow and what not to copy
Typical references for this folder:
- blooming or magical spread from one contact point
- environment waking up from a wand, raindrop, light pulse, or creature path
- touch-like transformation translated into authored cinematic motion
FILE:assets/examples/video-examples/scene-animation/_genre-assets.md
# Scene Animation Video Examples
Put future `scene-animation` reference videos in this folder.
Examples coming soon. This directory is intentionally reserved even though no video files have been added yet.
Examples coming soon. This directory is intentionally reserved even though no video files have been added yet.
Rules:
- each `.mp4` should have a sibling `.md` file with the same stem
- the sidecar `.md` should explain the progression beats, what changes over time, and where the emotional turn lands
- if the scene animation bridges from an H5 pattern, name that pattern explicitly
Use `../example-sidecar-template.md` as the baseline format.
FILE:assets/examples/video-examples/live-scene-doodle/ref-02.md
# Example: ref-02
## Genre
`live-scene-doodle`
## What It Looks Like
- airplane-window view with pink-purple dusk sky
- an open book and transparent cup rest on the tray table
- static handwritten title text sits in the upper area
- colorful small stars with trailing tails rise from the book toward the window and sky
## Motion Logic
- the real shot stays calm and observational
- star doodles repeatedly emerge from the book pages
- they travel upward in a clear directional stream toward the open sky outside the window
- the book acts as the emission source and the window acts as the escape destination
## Pacing
- short loop with constant upward star release
- the emotional turn lives in the transition from quiet reading scene to imaginative lift-off
- the clip should feel dreamy, not busy
## What To Borrow
- strong metaphorical path from one real object into open space
- using book pages as the origin of impossible doodle motion
- colorful but still simple doodle shapes
- clean vertical movement that makes the fantasy legible immediately
## What Not To Copy Literally
- the exact phrase `HOW TO CATCH A STAR`
- the exact airplane setting
- the exact colors or number of stars
- the assumption that all knowledge or imagination scenes must use stars
FILE:assets/examples/video-examples/live-scene-doodle/ref-03.md
# Example: ref-03
## Genre
`live-scene-doodle`
## What It Looks Like
- a layered latte sits on a dark tabletop with moody lighting
- above the cup floats a simple white doodled sad cloud face
- white dashed rain drops fall from the cloud into the cup
- the cup rim is the key attachment boundary
## Motion Logic
- the real coffee shot stays still and cinematic
- the doodled cloud hovers in place above the drink
- dashed drops fall directly into the cup in a repeating loop
- the loop depends on clean vertical alignment between cloud, drops, and cup opening
## Pacing
- short repetitive loop
- the emotional effect is immediate: bitterness or sadness becomes a tiny weather system
- the motion should stay restrained and melancholy rather than playful-chaotic
## What To Borrow
- one-object one-metaphor clarity
- emotional weather attached to a drink
- precise alignment between doodle endpoint and cup rim
- pure white linework against dark cinematic footage
## What Not To Copy Literally
- the exact sad-face cloud expression
- the exact latte glass shape
- the exact amount of rain
- the assumption that all bitter or lonely scenes should use rain
FILE:assets/examples/video-examples/live-scene-doodle/ref-04.md
# Example: ref-04
## Genre
`live-scene-doodle`
## What It Looks Like
- a red drink with thick white foam sits on a wooden coaster on a cyan tabletop
- nearby lies a small hand-drawn card
- fluorescent green, blue, and yellow doodle fireworks keep blooming above the foam
- the foam top acts as the ignition point for the doodle bursts
## Motion Logic
- the real tabletop still life remains stable
- tiny line fireworks repeatedly bloom from the same zone above the drink
- each burst appears, expands, and disappears quickly before the next begins
- the motion reads like the drink's taste or excitement escaping upward
## Pacing
- short repeating celebratory loop
- the emotional turn is micro-celebration rather than full spectacle
- timing should be crisp enough to feel sparkly but not crowded
## What To Borrow
- foam or surface used as a believable launch point
- color-synced neon doodles in a brighter real scene
- contrast between quiet product-style shot and playful celebratory overlay
- repeated small bursts instead of one giant event
## What Not To Copy Literally
- the exact drink color or coaster setup
- the exact firework shape or palette
- the exact tabletop color
- the assumption that all celebration overlays should be fireworks
FILE:assets/examples/video-examples/live-scene-doodle/ref-01.md
# Example: ref-01
## Genre
`live-scene-doodle`
## What It Looks Like
- a hand holds a white cosmos flower against a dark gray background
- the real scene is sparse, close-up, and softly lit
- white and pink handwritten English words and star-like marks hover around the flower petals
- the flower center acts as the physical anchor for the doodle field
## Motion Logic
- the live-action shot stays mostly still
- doodled words and small symbols orbit or drift lightly around the flower
- the motion is small and cyclical, like a soft spring breeze around a real object
## Pacing
- short loop
- the emotional turn lands immediately through the contrast between still realism and floating doodle warmth
- the loop should feel gentle rather than eventful
## What To Borrow
- flower as real-world anchor
- minimal handwritten overlay instead of dense decoration
- soft orbiting motion near the physical edges of petals
- use of negative space behind the subject
## What Not To Copy Literally
- the exact words `Spring` or `love`
- the exact flower species or framing
- the exact pink-and-white doodle placement
- the assumption that every healing scene should use handwritten English text
FILE:assets/examples/video-examples/live-scene-doodle/ref-05.md
# Example: ref-05
## Genre
`live-scene-doodle`
## What It Looks Like
- a vertical three-panel landscape composition shows green mountains, rider, meadow, and forest
- a giant white doodled dandelion stretches across the segmented scenic frames
- seeds drift from one side of the composition to the other
- the stitched panorama itself becomes the field the doodle crosses
## Motion Logic
- the landscape base remains wide and quiet
- the large doodled dandelion stays partly anchored while seeds peel away and drift across the multi-panel frame
- the movement direction is wind-led and continuous, cutting across the segmented real images
- the emotional effect comes from one soft impossible drawing unifying separate scenic panels
## Pacing
- short wind-driven loop
- the emotional turn is scenic calm becoming poetic motion
- the drift should feel long enough to cross the frame clearly, but still loop cleanly
## What To Borrow
- oversized doodle crossing multiple real-image regions
- one clear wind direction
- large-scale simple line drawing over panoramic natural footage
- using the overlay to unify segmented composition
## What Not To Copy Literally
- the exact dandelion symbol
- the exact three-panel split
- the exact landscape type or rider presence
- the assumption that all large landscape overlays should use seeds or white line art
FILE:assets/examples/video-examples/live-scene-doodle/_genre-assets.md
# Live Scene Doodle Video Examples
Place reference `.mp4` files for the `live-scene-doodle` genre in this folder.
Rules:
- every `.mp4` must have a sibling `.md` sidecar file with the same stem
- the real footage should remain the visual base layer
- the doodle layer should stay simple, readable, and physically attached to a real anchor in the shot
- use the sidecar to explain:
- what the real anchor object or zone is
- what doodle metaphor is layered on top
- where the doodle begins or ends physically
- how the loop behaves
- what emotional contrast the clip creates
- what to borrow and what not to copy
Typical references for this folder:
- flowers, cups, books, tabletops, windows, landscapes, or small everyday scenes
- simple handwritten words, stars, weather symbols, fireworks, seeds, or childlike line drawings
- clips where reality stays calm and the doodle adds one magical impossibility
FILE:assets/examples/video-examples/object-micro-cinema/_genre-assets.md
# Object Micro Cinema Video Examples
Place reference `.mp4` files for the `object-micro-cinema` genre in this folder.
Examples coming soon. This directory is intentionally reserved even though no video files have been added yet.
Rules:
- every `.mp4` must have a sibling `.md` sidecar file with the same stem
- use the sidecar to explain:
- what the central object is
- how the object is revealed, opened, approached, or reframed
- what sub-elements appear and in what order
- whether camera movement matters
- what to borrow and what not to copy
Typical references for this folder:
- drawer, cabinet, shelf, mirror, book, card, keepsake, or box-based micro films
- object-centered reveal sequences where the object itself is the gift container
- short clips where one meaningful object unfolds a thesis
FILE:scripts/post-delivery.sh
#!/bin/bash
set -euo pipefail
# Usage: post-delivery.sh <gift-metadata-json> <setup-state-json>
# Performs guaranteed mechanical bookkeeping only:
# - update setup-state timestamps and recent_gifts
# - append to gift-history.jsonl
METADATA_FILE="-"
SETUP_STATE_FILE="-"
if [ -z "$METADATA_FILE" ] || [ -z "$SETUP_STATE_FILE" ]; then
echo "Usage: post-delivery.sh <gift-metadata-json> <setup-state-json>" >&2
exit 1
fi
if [ ! -f "$METADATA_FILE" ]; then
echo "metadata file not found: $METADATA_FILE" >&2
exit 1
fi
python3 - "$METADATA_FILE" "$SETUP_STATE_FILE" <<'PY'
import json
import sys
from datetime import datetime, timezone
from pathlib import Path
meta_path = Path(sys.argv[1]).expanduser()
setup_path = Path(sys.argv[2]).expanduser()
history_path = setup_path.parent / "gift-history.jsonl"
def now_iso() -> str:
return datetime.now(timezone.utc).astimezone().isoformat(timespec="seconds")
def read_json(path: Path):
if not path.exists():
return {}
return json.loads(path.read_text(encoding="utf-8"))
def nonempty_dict(value):
if not isinstance(value, dict):
return {}
return {k: v for k, v in value.items() if v not in ("", None, [])}
TEXT_PLAY_OUTPUT_SHAPES = {
"worldbuilder": "text-play-worldbuilder",
"one-word-worldbuilder": "text-play-worldbuilder",
"riddle": "text-play-riddle",
"riddle-chain": "text-play-riddle",
"emoji-riddle": "text-play-riddle",
"emoji-riddle-chain": "text-play-riddle",
"micro-story": "text-play-micro-story",
"relay-story": "text-play-micro-story",
"micro-adventure": "text-play-micro-story",
"three-choice-micro-adventure": "text-play-micro-story",
"choose-your-own-adventure": "text-play-micro-story",
"roleplay": "text-play-roleplay",
"role-play": "text-play-roleplay",
"roleplay-micro-theater": "text-play-roleplay",
"role-play-micro-theater": "text-play-roleplay",
"micro-theater": "text-play-roleplay",
}
def infer_text_play_output_shape(text_play_type: str) -> str:
normalized = text_play_type.strip().lower().replace("_", "-")
if not normalized:
return "text-play-micro-story"
return TEXT_PLAY_OUTPUT_SHAPES.get(normalized, "text-play-micro-story")
def merge_from_meta(explicit_entry, keep_keys):
base_entry = {k: meta[k] for k in keep_keys if k in meta and meta[k] not in ("", None, [])}
return {**base_entry, **nonempty_dict(explicit_entry)}
def apply_runtime_defaults(entry):
pattern_or_format = str(entry.get("pattern_or_format") or meta.get("pattern_or_format") or "").strip()
if pattern_or_format != "text-play":
return entry
for key in [
"text_play_type",
"text_play_turn_count",
"text_play_completed",
"text_play_exit_reason",
]:
if key not in entry and meta.get(key) not in ("", None, []):
entry[key] = meta[key]
text_play_type = str(entry.get("text_play_type") or "").strip()
entry.setdefault("output_shape", infer_text_play_output_shape(text_play_type))
entry.setdefault("visual_style", "chat-native")
entry.setdefault("content_direction", "play")
return entry
meta = read_json(meta_path)
setup = read_json(setup_path)
timestamp = (
meta.get("sent_at")
or meta.get("recorded_at")
or meta.get("timestamp")
or now_iso()
)
summary = str(meta.get("summary") or meta.get("last_gift_summary") or "").strip()
trigger_mode = str(meta.get("trigger_mode") or meta.get("last_run_mode") or "unknown").strip()
decision = str(meta.get("decision") or "sent").strip()
recent_limit = int(setup.get("recent_gifts_limit") or 30)
recent_gifts = list(setup.get("recent_gifts") or [])
recent_entry = meta.get("recent_gift_entry")
recent_keep_keys = [
"sent_at",
"trigger_mode",
"gift_weight",
"narrative_role",
"tone",
"pattern_or_format",
"output_shape",
"visual_style",
"content_direction",
"content_tags",
"emotional_direction",
"summary",
"visual_elements",
"concept_family",
"concept_theme",
"text_play_type",
"text_play_turn_count",
"text_play_completed",
"text_play_exit_reason",
]
recent_entry = merge_from_meta(recent_entry, recent_keep_keys)
recent_entry = apply_runtime_defaults(recent_entry)
recent_entry.setdefault("sent_at", timestamp)
recent_entry.setdefault("trigger_mode", trigger_mode)
if summary:
recent_entry.setdefault("summary", summary)
recent_gifts.append(recent_entry)
setup["recent_gifts"] = recent_gifts[-recent_limit:]
setup["last_sent_at"] = timestamp
setup["last_gift_summary"] = summary
setup["last_run_at"] = timestamp
setup["last_run_mode"] = trigger_mode
setup["last_run_outcome"] = decision
setup_path.parent.mkdir(parents=True, exist_ok=True)
setup_path.write_text(json.dumps(setup, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
history_record = meta.get("history_record")
history_keep_keys = [
"record_type",
"recorded_at",
"sent_at",
"trigger_mode",
"decision",
"gift_weight",
"narrative_role",
"tone",
"pattern_or_format",
"output_shape",
"visual_style",
"content_direction",
"content_tags",
"emotional_direction",
"used_memory_dates",
"used_source_quotes",
"used_source_images",
"summary",
"why_it_mattered",
"quality_note",
"visual_elements",
"concept_family",
"concept_theme",
"image_mode",
"video_mode",
"generate_audio",
"text_play_type",
"text_play_turn_count",
"text_play_completed",
"text_play_exit_reason",
]
history_record = merge_from_meta(history_record, history_keep_keys)
history_record = apply_runtime_defaults(history_record)
history_record.setdefault("record_type", "gift")
history_record.setdefault("recorded_at", timestamp)
history_record.setdefault("sent_at", timestamp)
history_record.setdefault("trigger_mode", trigger_mode)
history_record.setdefault("decision", decision)
if summary:
history_record.setdefault("summary", summary)
history_path.parent.mkdir(parents=True, exist_ok=True)
with history_path.open("a", encoding="utf-8") as fh:
fh.write(json.dumps(history_record, ensure_ascii=False) + "\n")
PY
FILE:scripts/fetch-music.sh
#!/bin/bash
set -euo pipefail
# Usage: fetch-music.sh <query> <output-path> [max-duration-seconds] [setup-state-file]
# Example: fetch-music.sh "warm piano loop" ./music.mp3 30 ./setup-state.json
# Returns the output path on success, empty on failure.
QUERY="-"
OUTPUT="-"
MAX_DUR="-30"
SETUP_STATE="-"
if [ -z "$QUERY" ] || [ -z "$OUTPUT" ]; then
echo "Usage: fetch-music.sh <query> <output-path> [max-duration] [setup-state]" >&2
exit 1
fi
# Try to get API token from setup-state or environment
API_TOKEN=""
if [ -n "$SETUP_STATE" ] && [ -f "$SETUP_STATE" ]; then
API_TOKEN="$(python3 -c "
import json, sys
from pathlib import Path
try:
d = json.loads(Path(sys.argv[1]).read_text())
t = d.get('tools', {}).get('freesound', {})
print(t.get('api_key', '') or t.get('token', ''))
except: print('')
" "$SETUP_STATE")"
fi
if [ -z "$API_TOKEN" ] && [ -n "-" ]; then
API_TOKEN="$FREESOUND_API_KEY"
fi
if [ -z "$API_TOKEN" ]; then
echo "" # empty = no token, caller should fallback
exit 0
fi
# Search Freesound with progressive query simplification
# If the full query returns no results, try with fewer words
search_freesound() {
local q="$1"
local url="https://freesound.org/apiv2/search/text/?query=$(echo "$q" | tr ' ' '+')&fields=id,name,duration,previews&page_size=10&token=API_TOKEN"
curl -s "$url" | python3 -c "
import json, sys
max_dur = float(sys.argv[1])
d = json.load(sys.stdin)
for r in d.get('results', []):
if 5 <= r['duration'] <= max_dur:
url = r.get('previews', {}).get('preview-hq-mp3', '')
if url:
print(url)
break
" "$MAX_DUR" 2>/dev/null || true
}
PREVIEW_URL="$(search_freesound "$QUERY")"
# If no results, progressively drop words from the end and retry
if [ -z "$PREVIEW_URL" ]; then
WORDS=($QUERY)
WORD_COUNT=#WORDS[@]
while [ -z "$PREVIEW_URL" ] && [ "$WORD_COUNT" -gt 1 ]; do
WORD_COUNT=$((WORD_COUNT - 1))
SHORTER_QUERY="0:$WORD_COUNT"
PREVIEW_URL="$(search_freesound "$SHORTER_QUERY")"
done
fi
if [ -z "$PREVIEW_URL" ]; then
echo "" # empty = nothing found even after simplification
exit 0
fi
# Filename sanity check — reject alert/notification sounds
FILENAME="$(basename "$PREVIEW_URL")"
if echo "$FILENAME" | grep -qiE 'alert|bell|notif|alarm|siren|horn|beep|click|ring|train|whistle'; then
# Suspicious filename, likely not background music. Try next result or fallback.
echo ""
exit 0
fi
# Download preview
curl -s "$PREVIEW_URL" -o "$OUTPUT" 2>/dev/null
if [ -f "$OUTPUT" ] && [ -s "$OUTPUT" ]; then
echo "$OUTPUT"
else
echo ""
fi
FILE:scripts/fetch-asset-bundle.sh
#!/bin/bash
set -euo pipefail
# Usage: fetch-asset-bundle.sh <bundle-key> [base-dir] [manifest-path]
# Example: fetch-asset-bundle.sh "image-examples/meme-sticker" "/path/to/repo"
# Prints the extracted target directory on success.
BUNDLE_KEY="-"
BASE_DIR="-"
MANIFEST_PATH="-"
if [ -z "$BUNDLE_KEY" ]; then
echo "Usage: fetch-asset-bundle.sh <bundle-key> [base-dir] [manifest-path]" >&2
exit 1
fi
if [ -z "$BASE_DIR" ]; then
BASE_DIR="$(cd "$(dirname "$0")/.." && pwd)"
fi
if [ -z "$MANIFEST_PATH" ]; then
MANIFEST_PATH="$BASE_DIR/references/asset-manifest.json"
fi
if [ ! -f "$MANIFEST_PATH" ]; then
echo "asset manifest not found: $MANIFEST_PATH" >&2
exit 1
fi
bundle_url="$(python3 - "$MANIFEST_PATH" "$BUNDLE_KEY" <<'PY'
import json
import sys
from pathlib import Path
manifest = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
print(manifest.get(sys.argv[2], ""))
PY
)"
if [ -z "$bundle_url" ]; then
echo "bundle key not found in manifest: $BUNDLE_KEY" >&2
exit 1
fi
target_dir=""
case "$BUNDLE_KEY" in
audio)
target_dir="$BASE_DIR/assets/audio"
;;
image-examples/*|video-examples/*)
target_dir="$BASE_DIR/assets/examples/$BUNDLE_KEY"
;;
examples/*)
target_dir="$BASE_DIR/assets/$BUNDLE_KEY"
;;
*)
echo "unsupported bundle key: $BUNDLE_KEY" >&2
exit 1
;;
esac
if [ -d "$target_dir" ] && [ -n "$(ls -A "$target_dir" 2>/dev/null || true)" ]; then
printf '%s\n' "$target_dir"
exit 0
fi
mkdir -p "$target_dir"
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT
zip_path="$tmpdir/bundle.zip"
case "$bundle_url" in
http://*|https://*)
curl -fsSL "$bundle_url" -o "$zip_path"
;;
*)
cp "$bundle_url" "$zip_path"
;;
esac
unzip -oq "$zip_path" -d "$target_dir"
printf '%s\n' "$target_dir"
FILE:scripts/deploy.sh
#!/bin/bash
set -euo pipefail
# Usage: deploy.sh <html-file> <domain> [provider]
# Example: deploy.sh ./gift.html your-gifts.surge.sh surge
HTML_FILE="-"
DOMAIN="-"
PROVIDER="-surge"
SURGE_DEPLOY_MAX_ATTEMPTS="-2"
SURGE_DEPLOY_RETRY_DELAY_SECONDS="-3"
if [ -z "$HTML_FILE" ] || [ -z "$DOMAIN" ]; then
echo "Usage: deploy.sh <html-file> <domain> [provider]" >&2
exit 1
fi
if [ ! -f "$HTML_FILE" ]; then
echo "HTML file not found: $HTML_FILE" >&2
exit 1
fi
case "$PROVIDER" in
surge)
if ! command -v surge >/dev/null 2>&1; then
echo "surge is not installed. Run: npm install -g surge" >&2
exit 1
fi
TMPDIR="$(mktemp -d)"
trap 'rm -rf "$TMPDIR"' EXIT
cp "$HTML_FILE" "$TMPDIR/index.html"
ATTEMPT=1
while [ "$ATTEMPT" -le "$SURGE_DEPLOY_MAX_ATTEMPTS" ]; do
set +e
SURGE_OUTPUT="$(surge "$TMPDIR" --domain "$DOMAIN" 2>&1)"
STATUS=$?
set -e
if [ "$STATUS" -eq 0 ]; then
printf '%s\n' "$SURGE_OUTPUT"
echo "https://$DOMAIN"
exit 0
fi
printf '%s\n' "$SURGE_OUTPUT" >&2
if [ "$ATTEMPT" -lt "$SURGE_DEPLOY_MAX_ATTEMPTS" ]; then
echo "surge deploy attempt $ATTEMPT failed; retrying in SURGE_DEPLOY_RETRY_DELAY_SECONDSs..." >&2
sleep "$SURGE_DEPLOY_RETRY_DELAY_SECONDS"
else
echo "surge deploy failed after SURGE_DEPLOY_MAX_ATTEMPTS attempts" >&2
exit "$STATUS"
fi
ATTEMPT=$((ATTEMPT + 1))
done
;;
*)
echo "Unsupported provider: $PROVIDER" >&2
exit 1
;;
esac
FILE:scripts/render-image.sh
#!/bin/bash
set -euo pipefail
# Usage: render-image.sh <brief-json-file> <setup-state-file> [curl-bin]
BRIEF_FILE="-"
SETUP_STATE_FILE="-"
CURL_BIN="-curl"
if [ -z "$BRIEF_FILE" ] || [ -z "$SETUP_STATE_FILE" ]; then
echo "Usage: render-image.sh <brief-json-file> <setup-state-file> [curl-bin]" >&2
exit 1
fi
normalize_warning() {
python3 -c 'import sys; print(sys.stdin.read().strip().replace("\n", " | "))'
}
print_result() {
python3 - "$@" <<'PY'
import json
import sys
(
render_mode,
image_urls_json,
tracking_url,
provider,
provider_path,
model,
genre,
fallback_reason,
warning,
) = sys.argv[1:]
try:
image_urls = json.loads(image_urls_json)
except Exception:
image_urls = []
print(
json.dumps(
{
"render_mode": render_mode,
"image_urls": image_urls,
"tracking_url": tracking_url,
"provider": provider,
"provider_path": provider_path,
"model": model,
"genre": genre,
"fallback_reason": fallback_reason,
"warning": warning,
},
ensure_ascii=True,
)
)
PY
}
read_runtime_bundle() {
python3 - "$BRIEF_FILE" "$SETUP_STATE_FILE" <<'PY'
import json
import sys
from pathlib import Path
brief_path = Path(sys.argv[1])
setup_path = Path(sys.argv[2]).expanduser()
def emit(**kwargs):
print(json.dumps(kwargs, ensure_ascii=True))
def build_prompt(brief):
user_input = str(brief.get("user_input") or "").strip()
scene_description = str(brief.get("scene_description") or "").strip()
genre = str(brief.get("image_genre") or "").strip()
style_hint = str(brief.get("style_hint") or "").strip()
aspect_ratio_hint = str(brief.get("aspect_ratio_hint") or "").strip()
characters = brief.get("characters")
pov = str(brief.get("pov") or "").strip()
text_overlay_spec = brief.get("text_overlay_spec")
primary = user_input or scene_description
if not primary:
return ""
parts = [primary]
if genre:
parts.append(f"Image genre: {genre}.")
if style_hint:
parts.append(f"Visual style guidance: {style_hint}.")
if aspect_ratio_hint:
parts.append(f"Target aspect ratio: {aspect_ratio_hint}.")
if isinstance(characters, list) and characters:
character_lines = []
for character in characters:
if not isinstance(character, dict):
continue
role = str(character.get("role") or "").strip()
species = str(character.get("species") or "").strip()
color = str(character.get("color") or "").strip()
features = character.get("features")
feature_text = ""
if isinstance(features, list):
feature_text = ", ".join(str(item).strip() for item in features if str(item).strip())
elif isinstance(features, str):
feature_text = features.strip()
descriptors = [item for item in [species, color] if item]
line = ""
if role and descriptors:
line = f"{role}: {' '.join(descriptors)}"
elif role:
line = f"{role}: established recurring character"
elif descriptors:
line = " ".join(descriptors)
if feature_text:
if line:
line += f" ({feature_text})"
else:
line = feature_text
if line:
character_lines.append(line)
if character_lines:
parts.append("Characters in scene: " + "; ".join(character_lines) + ".")
if pov:
parts.append(f"Composition point of view: {pov}.")
if isinstance(text_overlay_spec, dict) and text_overlay_spec:
text_lines = []
wording = (
text_overlay_spec.get("text")
or text_overlay_spec.get("wording")
or text_overlay_spec.get("content")
or ""
)
placement = str(text_overlay_spec.get("placement") or "")
size = str(text_overlay_spec.get("size") or "")
font_feel = str(text_overlay_spec.get("font_feel") or text_overlay_spec.get("font") or "")
language = str(text_overlay_spec.get("language") or "")
if wording:
text_lines.append(f"On-image text: {wording}")
if language:
text_lines.append(f"Text language: {language}")
if placement:
text_lines.append(f"Text placement: {placement}")
if size:
text_lines.append(f"Text size: {size}")
if font_feel:
text_lines.append(f"Typography feel: {font_feel}")
if text_lines:
parts.append(" ".join(text_lines) + ".")
return "\n".join(parts).strip()
try:
brief = json.loads(brief_path.read_text(encoding="utf-8"))
except Exception:
emit(status="fallback", fallback_reason="brief_invalid", warning="brief_invalid")
raise SystemExit(0)
if not setup_path.exists():
emit(status="fallback", fallback_reason="setup_state_missing", warning="setup_state_missing")
raise SystemExit(0)
try:
setup = json.loads(setup_path.read_text(encoding="utf-8"))
except Exception:
emit(status="fallback", fallback_reason="setup_state_invalid", warning="setup_state_invalid")
raise SystemExit(0)
image = setup.get("image") or {}
prompt = build_prompt(brief)
if not prompt:
emit(status="fallback", fallback_reason="empty_prompt", warning="")
raise SystemExit(0)
emit(
status="ready",
enabled=bool(image.get("enabled")),
provider=str(image.get("provider") or "").strip(),
model=str(image.get("model") or "").strip(),
api_key_source=str(image.get("api_key_source") or "").strip(),
api_key=str(image.get("api_key") or ""),
genre=str(brief.get("image_genre") or "").strip(),
prompt=prompt,
aspect_ratio_hint=str(brief.get("aspect_ratio_hint") or "").strip(),
output_dir=str((setup_path.parent / "generated-images").resolve()),
)
PY
}
detect_provider_path() {
python3 - "$1" <<'PY'
import json
import os
import re
import sys
runtime = json.loads(sys.argv[1])
def emit(**kwargs):
print(json.dumps(kwargs, ensure_ascii=True))
if runtime.get("status") != "ready":
emit(status="fallback", fallback_reason=runtime.get("fallback_reason", "runtime_invalid"), warning=runtime.get("warning", ""))
raise SystemExit(0)
enabled = bool(runtime.get("enabled"))
provider = str(runtime.get("provider") or "").strip().lower()
model = str(runtime.get("model") or "").strip()
api_key_source = str(runtime.get("api_key_source") or "").strip()
api_key = str(runtime.get("api_key") or "")
if not enabled:
emit(status="fallback", fallback_reason="image_disabled", warning="")
raise SystemExit(0)
if not provider or not model:
emit(status="fallback", fallback_reason="image_config_incomplete", warning="")
raise SystemExit(0)
has_env_key = bool(api_key_source and os.environ.get(api_key_source))
has_inline_key = bool(api_key)
if not has_env_key and not has_inline_key:
emit(status="fallback", fallback_reason="image_api_key_missing", warning="image_api_key_missing")
raise SystemExit(0)
provider_path = ""
source_upper = api_key_source.upper()
if provider in {"gemini", "google", "gemini-direct", "google-direct"}:
provider_path = "gemini-direct"
elif provider in {"openrouter", "openrouter-image"}:
provider_path = "openrouter"
elif source_upper in {"GEMINI_API_KEY", "GOOGLE_API_KEY"}:
provider_path = "gemini-direct"
elif source_upper == "OPENROUTER_API_KEY":
provider_path = "openrouter"
elif re.search(r"gemini|google", provider):
provider_path = "gemini-direct"
elif re.search(r"openrouter", provider):
provider_path = "openrouter"
else:
emit(status="fallback", fallback_reason="image_provider_unsupported", warning="image_provider_unsupported")
raise SystemExit(0)
emit(status="ready", provider_path=provider_path)
PY
}
json_get() {
python3 - "$1" "$2" <<'PY'
import json
import sys
data = json.loads(sys.argv[1])
value = data.get(sys.argv[2], "")
if isinstance(value, bool):
print("true" if value else "false")
else:
print(str(value))
PY
}
parse_openrouter_images() {
local response_file="$1"
local output_dir="$2"
python3 - "$response_file" "$output_dir" <<'PY'
import base64
import json
import mimetypes
import sys
import uuid
from pathlib import Path
response_path = Path(sys.argv[1])
output_dir = Path(sys.argv[2])
output_dir.mkdir(parents=True, exist_ok=True)
def suffix_for_mime(mime_type: str) -> str:
guessed = mimetypes.guess_extension(mime_type or "")
return guessed or ".png"
def save_base64_url(url: str) -> str:
header, data = url.split(",", 1)
mime_type = header.split(";")[0].split(":", 1)[1] if ":" in header else "image/png"
raw = base64.b64decode(data)
target = output_dir / f"openrouter-{uuid.uuid4().hex}{suffix_for_mime(mime_type)}"
target.write_bytes(raw)
return str(target)
def collect_urls(message):
urls = []
for item in message.get("images") or []:
if not isinstance(item, dict):
continue
image_payload = item.get("image_url") or item.get("imageUrl") or {}
if isinstance(image_payload, dict):
url = image_payload.get("url") or ""
if isinstance(url, str) and url:
urls.append(url)
content = message.get("content")
if isinstance(content, list):
for part in content:
if not isinstance(part, dict):
continue
if part.get("type") == "image_url":
image_payload = part.get("image_url") or part.get("imageUrl") or {}
if isinstance(image_payload, dict):
url = image_payload.get("url") or ""
if isinstance(url, str) and url:
urls.append(url)
elif part.get("type") == "image":
source = part.get("source") or {}
if isinstance(source, dict) and source.get("type") == "base64":
data = source.get("data") or ""
mime_type = source.get("media_type") or source.get("mime_type") or "image/png"
if data:
urls.append(f"data:{mime_type};base64,{data}")
return urls
try:
response = json.loads(response_path.read_text(encoding="utf-8"))
except Exception:
print(json.dumps({"image_urls": [], "warning": "response_invalid"}, ensure_ascii=True))
raise SystemExit(0)
choices = response.get("choices") or []
if not choices:
print(json.dumps({"image_urls": [], "warning": "no_choices"}, ensure_ascii=True))
raise SystemExit(0)
message = (choices[0] or {}).get("message") or {}
raw_urls = collect_urls(message)
# Also check message.images[] (OpenRouter/Gemini sometimes returns images here)
for img_item in (message.get("images") or []):
if isinstance(img_item, dict):
img_url_obj = img_item.get("image_url")
if isinstance(img_url_obj, dict):
url = img_url_obj.get("url", "")
elif isinstance(img_url_obj, str):
url = img_url_obj
else:
url = img_item.get("url", "")
if url:
raw_urls.append(url)
elif isinstance(img_item, str) and img_item:
raw_urls.append(img_item)
image_urls = []
for url in raw_urls:
if not isinstance(url, str) or not url:
continue
if url.startswith("data:image/"):
image_urls.append(save_base64_url(url))
else:
image_urls.append(url)
print(json.dumps({"image_urls": image_urls, "warning": ""}, ensure_ascii=True))
PY
}
parse_gemini_images() {
local response_file="$1"
local output_dir="$2"
python3 - "$response_file" "$output_dir" <<'PY'
import base64
import json
import mimetypes
import sys
import uuid
from pathlib import Path
response_path = Path(sys.argv[1])
output_dir = Path(sys.argv[2])
output_dir.mkdir(parents=True, exist_ok=True)
def suffix_for_mime(mime_type: str) -> str:
guessed = mimetypes.guess_extension(mime_type or "")
return guessed or ".png"
def save_inline_image(mime_type: str, data: str) -> str:
raw = base64.b64decode(data)
target = output_dir / f"gemini-{uuid.uuid4().hex}{suffix_for_mime(mime_type)}"
target.write_bytes(raw)
return str(target)
try:
response = json.loads(response_path.read_text(encoding="utf-8"))
except Exception:
print(json.dumps({"image_urls": [], "warning": "response_invalid"}, ensure_ascii=True))
raise SystemExit(0)
candidates = response.get("candidates") or []
parts = []
for candidate in candidates:
if not isinstance(candidate, dict):
continue
content = candidate.get("content") or {}
if isinstance(content, dict):
candidate_parts = content.get("parts") or []
if isinstance(candidate_parts, list):
parts.extend(candidate_parts)
if not parts and isinstance(response.get("parts"), list):
parts = response.get("parts") or []
image_urls = []
for part in parts:
if not isinstance(part, dict):
continue
inline_data = part.get("inline_data") or part.get("inlineData") or {}
if not isinstance(inline_data, dict):
continue
mime_type = inline_data.get("mime_type") or inline_data.get("mimeType") or "image/png"
data = inline_data.get("data") or ""
if data:
image_urls.append(save_inline_image(mime_type, data))
print(json.dumps({"image_urls": image_urls, "warning": ""}, ensure_ascii=True))
PY
}
run_openrouter() {
local runtime_json="$1"
local provider model genre api_key_source api_key prompt aspect_ratio output_dir
local payload_file response_file error_file payload_json response_info image_urls_json warning
provider="$(json_get "$runtime_json" "provider")"
model="$(json_get "$runtime_json" "model")"
genre="$(json_get "$runtime_json" "genre")"
api_key_source="$(json_get "$runtime_json" "api_key_source")"
api_key="$(json_get "$runtime_json" "api_key")"
prompt="$(json_get "$runtime_json" "prompt")"
aspect_ratio="$(json_get "$runtime_json" "aspect_ratio_hint")"
output_dir="$(json_get "$runtime_json" "output_dir")"
if [ -n "$api_key_source" ] && [ -n "-" ]; then
api_key="!api_key_source"
fi
if [ -z "$api_key" ]; then
print_result "fallback_h5" "[]" "" "$provider" "openrouter" "$model" "$genre" "api_key_not_found" ""
return
fi
if [ -z "$prompt" ]; then
print_result "fallback_h5" "[]" "" "$provider" "openrouter" "$model" "$genre" "empty_prompt" ""
return
fi
payload_file="$(mktemp)"
response_file="$(mktemp)"
error_file="$(mktemp)"
python3 - "$payload_file" "$model" "$prompt" "$aspect_ratio" <<'PY'
import json
import sys
from pathlib import Path
payload_path = Path(sys.argv[1])
model = sys.argv[2]
prompt = sys.argv[3]
aspect_ratio = sys.argv[4]
payload = {
"model": model,
"messages": [
{
"role": "user",
"content": prompt,
}
],
"modalities": ["image", "text"],
}
if aspect_ratio:
payload["image_config"] = {"aspect_ratio": aspect_ratio}
payload_path.write_text(json.dumps(payload, ensure_ascii=False), encoding="utf-8")
PY
if ! "$CURL_BIN" -fsS -X POST "https://openrouter.ai/api/v1/chat/completions" \
-H "Authorization: Bearer $api_key" \
-H "Content-Type: application/json" \
--data @"$payload_file" >"$response_file" 2>"$error_file"; then
warning="$(normalize_warning <"$error_file")"
rm -f "$payload_file" "$response_file" "$error_file"
print_result "fallback_h5" "[]" "" "$provider" "openrouter" "$model" "$genre" "api_call_failed" "$warning"
return
fi
response_info="$(parse_openrouter_images "$response_file" "$output_dir")"
image_urls_json="$(python3 - "$response_info" <<'PY'
import json
import sys
print(json.dumps(json.loads(sys.argv[1]).get("image_urls") or []))
PY
)"
warning="$(python3 - "$response_info" <<'PY'
import json
import sys
print(str(json.loads(sys.argv[1]).get("warning") or ""))
PY
)"
rm -f "$payload_file" "$response_file" "$error_file"
if [ "$image_urls_json" = "[]" ]; then
print_result "fallback_h5" "[]" "" "$provider" "openrouter" "$model" "$genre" "no_image_in_response" "$warning"
return
fi
print_result "image_urls" "$image_urls_json" "" "$provider" "openrouter" "$model" "$genre" "" "$warning"
}
run_gemini_direct() {
local runtime_json="$1"
local provider model genre api_key_source api_key prompt output_dir
local payload_file response_file error_file response_info image_urls_json warning
provider="$(json_get "$runtime_json" "provider")"
model="$(json_get "$runtime_json" "model")"
genre="$(json_get "$runtime_json" "genre")"
api_key_source="$(json_get "$runtime_json" "api_key_source")"
api_key="$(json_get "$runtime_json" "api_key")"
prompt="$(json_get "$runtime_json" "prompt")"
output_dir="$(json_get "$runtime_json" "output_dir")"
if [ -n "$api_key_source" ] && [ -n "-" ]; then
api_key="!api_key_source"
fi
if [ -z "$api_key" ]; then
print_result "fallback_h5" "[]" "" "$provider" "gemini-direct" "$model" "$genre" "api_key_not_found" ""
return
fi
if [ -z "$prompt" ]; then
print_result "fallback_h5" "[]" "" "$provider" "gemini-direct" "$model" "$genre" "empty_prompt" ""
return
fi
payload_file="$(mktemp)"
response_file="$(mktemp)"
error_file="$(mktemp)"
python3 - "$payload_file" "$prompt" <<'PY'
import json
import sys
from pathlib import Path
payload_path = Path(sys.argv[1])
prompt = sys.argv[2]
payload = {
"contents": [
{
"parts": [
{
"text": prompt,
}
]
}
]
}
payload_path.write_text(json.dumps(payload, ensure_ascii=False), encoding="utf-8")
PY
if ! "$CURL_BIN" -fsS -X POST "https://generativelanguage.googleapis.com/v1beta/models/$model:generateContent" \
-H "x-goog-api-key: $api_key" \
-H "Content-Type: application/json" \
--data @"$payload_file" >"$response_file" 2>"$error_file"; then
warning="$(normalize_warning <"$error_file")"
rm -f "$payload_file" "$response_file" "$error_file"
print_result "fallback_h5" "[]" "" "$provider" "gemini-direct" "$model" "$genre" "api_call_failed" "$warning"
return
fi
response_info="$(parse_gemini_images "$response_file" "$output_dir")"
image_urls_json="$(python3 - "$response_info" <<'PY'
import json
import sys
print(json.dumps(json.loads(sys.argv[1]).get("image_urls") or []))
PY
)"
warning="$(python3 - "$response_info" <<'PY'
import json
import sys
print(str(json.loads(sys.argv[1]).get("warning") or ""))
PY
)"
rm -f "$payload_file" "$response_file" "$error_file"
if [ "$image_urls_json" = "[]" ]; then
print_result "fallback_h5" "[]" "" "$provider" "gemini-direct" "$model" "$genre" "no_image_in_response" "$warning"
return
fi
print_result "image_urls" "$image_urls_json" "" "$provider" "gemini-direct" "$model" "$genre" "" "$warning"
}
dispatch_provider_path() {
local runtime_json="$1"
local provider_path="$2"
case "$provider_path" in
gemini-direct)
run_gemini_direct "$runtime_json"
;;
openrouter)
run_openrouter "$runtime_json"
;;
*)
print_result \
"fallback_h5" \
"[]" \
"" \
"$(json_get "$runtime_json" "provider")" \
"$provider_path" \
"$(json_get "$runtime_json" "model")" \
"$(json_get "$runtime_json" "genre")" \
"image_provider_unsupported" \
"image_provider_unsupported"
;;
esac
}
RUNTIME_JSON="$(read_runtime_bundle)"
if [ "$(json_get "$RUNTIME_JSON" "status")" != "ready" ]; then
print_result \
"fallback_h5" \
"[]" \
"" \
"" \
"" \
"" \
"" \
"$(json_get "$RUNTIME_JSON" "fallback_reason")" \
"$(json_get "$RUNTIME_JSON" "warning")"
exit 0
fi
DETECTION_JSON="$(detect_provider_path "$RUNTIME_JSON")"
if [ "$(json_get "$DETECTION_JSON" "status")" != "ready" ]; then
print_result \
"fallback_h5" \
"[]" \
"" \
"$(json_get "$RUNTIME_JSON" "provider")" \
"" \
"$(json_get "$RUNTIME_JSON" "model")" \
"$(json_get "$RUNTIME_JSON" "genre")" \
"$(json_get "$DETECTION_JSON" "fallback_reason")" \
"$(json_get "$DETECTION_JSON" "warning")"
exit 0
fi
dispatch_provider_path "$RUNTIME_JSON" "$(json_get "$DETECTION_JSON" "provider_path")"
FILE:scripts/render-video.sh
#!/bin/bash
set -euo pipefail
# Usage: render-video.sh <brief-json-file> <setup-state-file> [curl-bin]
BRIEF_FILE="-"
SETUP_STATE_FILE="-"
CURL_BIN="-curl"
POLL_INTERVAL_SECONDS="-10"
TIMEOUT_SECONDS="-300"
if [ -z "$BRIEF_FILE" ] || [ -z "$SETUP_STATE_FILE" ]; then
echo "Usage: render-video.sh <brief-json-file> <setup-state-file> [curl-bin]" >&2
exit 1
fi
if [ ! -f "$BRIEF_FILE" ]; then
echo "Brief file not found: $BRIEF_FILE" >&2
exit 1
fi
normalize_warning() {
python3 -c 'import sys; print(sys.stdin.read().strip().replace("\n", " | "))'
}
print_result() {
python3 - "$@" <<'PY'
import json
import sys
(
render_mode,
video_url,
tracking_url,
provider,
model,
genre,
fallback_reason,
warning,
) = sys.argv[1:]
print(
json.dumps(
{
"render_mode": render_mode,
"video_url": video_url,
"tracking_url": tracking_url,
"provider": provider,
"model": model,
"genre": genre,
"fallback_reason": fallback_reason,
"warning": warning,
},
ensure_ascii=True,
)
)
PY
}
read_runtime_bundle() {
python3 - "$BRIEF_FILE" "$SETUP_STATE_FILE" <<'PY'
import json
import os
import re
import sys
from pathlib import Path
brief_path = Path(sys.argv[1])
setup_path = Path(sys.argv[2]).expanduser()
DEFAULT_API_BASE_URL = "https://ark.cn-beijing.volces.com/api/v3"
DEFAULT_VIDEO_MODEL = "doubao-seedance-1-5-pro-251215"
DEFAULT_TEXT_TO_VIDEO_MODEL = "doubao-seedance-1-0-pro-250528"
def emit(**kwargs):
print(json.dumps(kwargs, ensure_ascii=True))
def parse_duration_seconds(value: str) -> str:
text = (value or "").strip().lower()
match = re.search(r"(\d+)", text)
if not match:
return "5"
seconds = match.group(1)
return seconds
def build_prompt(brief):
user_input = str(brief.get("user_input") or "").strip()
scene_description = str(brief.get("scene_description") or "").strip()
genre = str(brief.get("video_genre") or "").strip()
motion_strategy = str(brief.get("motion_strategy") or "").strip()
duration_hint = str(brief.get("duration_hint") or "").strip()
style_hint = str(brief.get("style_hint") or "").strip()
aspect_ratio_hint = str(brief.get("aspect_ratio_hint") or "").strip()
loop = brief.get("loop")
primary = user_input or scene_description
if not primary:
return "", "", ""
lines = [primary]
if scene_description and scene_description != primary:
lines.append(f"Scene focus: {scene_description}.")
if genre:
lines.append(f"Video genre: {genre}.")
if motion_strategy:
lines.append(f"Motion strategy: {motion_strategy}.")
if style_hint:
lines.append(f"Visual style guidance: {style_hint}.")
if loop is True:
lines.append("Make the clip loop cleanly.")
elif loop is False:
lines.append("Do not force a loop unless the motion naturally resolves that way.")
ratio = aspect_ratio_hint if re.fullmatch(r"\d+:\d+", aspect_ratio_hint) else "adaptive"
duration_seconds = parse_duration_seconds(duration_hint)
return "\n".join(lines).strip(), ratio, duration_seconds
def normalize_video_mode(raw_mode: str, reference_image_url: str, first_frame_image_url: str, last_frame_image_url: str) -> str:
mode = (raw_mode or "").strip().lower()
aliases = {
"text-to-video": "text-to-video",
"text_only": "text-to-video",
"text-only": "text-to-video",
"t2v": "text-to-video",
"first-frame": "first-frame",
"first_frame": "first-frame",
"image-to-video": "first-frame",
"image_to_video": "first-frame",
"i2v": "first-frame",
"first-last-frame": "first-last-frame",
"first_last_frame": "first-last-frame",
"first+last-frame": "first-last-frame",
"first-last": "first-last-frame",
}
if mode in aliases:
return aliases[mode]
if first_frame_image_url and last_frame_image_url:
return "first-last-frame"
if reference_image_url or first_frame_image_url:
return "first-frame"
return "text-to-video"
def is_remote_url(value: str) -> bool:
return bool(re.match(r"^https?://", (value or "").strip(), re.IGNORECASE))
try:
brief = json.loads(brief_path.read_text(encoding="utf-8"))
except Exception:
emit(status="fallback", fallback_reason="brief_invalid", warning="brief_invalid")
raise SystemExit(0)
if not setup_path.exists():
emit(status="fallback", fallback_reason="setup_state_missing", warning="setup_state_missing")
raise SystemExit(0)
try:
setup = json.loads(setup_path.read_text(encoding="utf-8"))
except Exception:
emit(status="fallback", fallback_reason="setup_state_invalid", warning="setup_state_invalid")
raise SystemExit(0)
video = setup.get("video") or {}
enabled = bool(video.get("enabled"))
provider = str(video.get("provider") or "").strip().lower()
model = str(video.get("model") or "").strip()
api_base_url = str(video.get("api_base_url") or DEFAULT_API_BASE_URL).rstrip("/")
api_key_source = str(video.get("api_key_source") or "").strip()
api_key = str(video.get("api_key") or "")
genre = str(brief.get("video_genre") or "").strip()
video_model_override = str(brief.get("video_model") or "").strip()
reference_image_url = str(
brief.get("reference_image_url")
or brief.get("reference_frame_url")
or ""
).strip()
first_frame_image_url = str(brief.get("first_frame_image_url") or "").strip()
last_frame_image_url = str(brief.get("last_frame_image_url") or "").strip()
video_mode = normalize_video_mode(
str(brief.get("video_mode") or ""),
reference_image_url,
first_frame_image_url,
last_frame_image_url,
)
generate_audio = brief.get("generate_audio")
prompt, aspect_ratio_hint, duration_seconds = build_prompt(brief)
if not enabled:
emit(status="fallback", fallback_reason="video_disabled", warning="", provider=provider, model=model, genre=genre)
raise SystemExit(0)
if not provider or not model:
emit(status="fallback", fallback_reason="video_config_incomplete", warning="", provider=provider, model=model, genre=genre)
raise SystemExit(0)
if provider != "volcengine":
emit(
status="fallback",
fallback_reason="video_provider_unsupported",
warning="video_provider_unsupported",
provider=provider,
model=model,
genre=genre,
)
raise SystemExit(0)
has_env_key = bool(api_key_source and os.environ.get(api_key_source))
has_inline_key = bool(api_key)
if not has_env_key and not has_inline_key:
emit(
status="fallback",
fallback_reason="video_api_key_missing",
warning="video_api_key_missing",
provider=provider,
model=model,
genre=genre,
)
raise SystemExit(0)
if not prompt:
emit(status="fallback", fallback_reason="empty_prompt", warning="", provider=provider, model=model, genre=genre)
raise SystemExit(0)
if video_mode == "first-frame":
if not reference_image_url:
reference_image_url = first_frame_image_url
if not reference_image_url:
emit(
status="fallback",
fallback_reason="video_reference_image_missing",
warning="video_reference_image_missing",
provider=provider,
model=model,
genre=genre,
)
raise SystemExit(0)
if not is_remote_url(reference_image_url):
emit(
status="fallback",
fallback_reason="video_reference_image_not_url",
warning=f"video reference image must be a remote URL, got: {reference_image_url}",
provider=provider,
model=model,
genre=genre,
)
raise SystemExit(0)
if video_mode == "first-last-frame":
if not first_frame_image_url or not last_frame_image_url:
emit(
status="fallback",
fallback_reason="video_reference_frames_incomplete",
warning="video_reference_frames_incomplete",
provider=provider,
model=model,
genre=genre,
)
raise SystemExit(0)
if not is_remote_url(first_frame_image_url):
emit(
status="fallback",
fallback_reason="video_reference_image_not_url",
warning=f"video first frame image must be a remote URL, got: {first_frame_image_url}",
provider=provider,
model=model,
genre=genre,
)
raise SystemExit(0)
if not is_remote_url(last_frame_image_url):
emit(
status="fallback",
fallback_reason="video_reference_image_not_url",
warning=f"video last frame image must be a remote URL, got: {last_frame_image_url}",
provider=provider,
model=model,
genre=genre,
)
raise SystemExit(0)
base_model = model or DEFAULT_VIDEO_MODEL
if video_model_override:
request_model = video_model_override
elif video_mode == "text-to-video" and base_model == DEFAULT_VIDEO_MODEL:
request_model = DEFAULT_TEXT_TO_VIDEO_MODEL
else:
request_model = base_model
emit(
status="ready",
provider=provider,
model=request_model,
api_base_url=api_base_url,
api_key_source=api_key_source,
api_key=api_key,
request_model=request_model,
genre=genre,
prompt=prompt,
aspect_ratio_hint=aspect_ratio_hint,
duration_seconds=duration_seconds,
video_mode=video_mode,
reference_image_url=reference_image_url,
first_frame_image_url=first_frame_image_url,
last_frame_image_url=last_frame_image_url,
generate_audio=bool(generate_audio),
)
PY
}
json_get() {
python3 - "$1" "$2" <<'PY'
import json
import sys
data = json.loads(sys.argv[1])
value = data.get(sys.argv[2], "")
if isinstance(value, bool):
print("true" if value else "false")
else:
print(str(value))
PY
}
create_payload_file() {
python3 - "$1" "$2" <<'PY'
import json
import sys
from pathlib import Path
runtime = json.loads(sys.argv[1])
payload_path = Path(sys.argv[2])
payload = {
"model": runtime["request_model"],
"content": [
{
"type": "text",
"text": runtime["prompt"],
}
],
"ratio": runtime["aspect_ratio_hint"] or "adaptive",
"duration": int(runtime["duration_seconds"] or 5),
"watermark": False,
}
video_mode = str(runtime.get("video_mode") or "")
reference_image_url = str(runtime.get("reference_image_url") or "")
first_frame_image_url = str(runtime.get("first_frame_image_url") or "")
last_frame_image_url = str(runtime.get("last_frame_image_url") or "")
if video_mode == "first-frame" and reference_image_url:
payload["content"].append(
{
"type": "image_url",
"image_url": {
"url": reference_image_url,
},
}
)
elif video_mode == "first-last-frame":
payload["content"].append(
{
"type": "image_url",
"image_url": {
"url": first_frame_image_url,
},
"role": "first_frame",
}
)
payload["content"].append(
{
"type": "image_url",
"image_url": {
"url": last_frame_image_url,
},
"role": "last_frame",
}
)
if runtime.get("generate_audio") is True:
payload["generate_audio"] = True
payload_path.write_text(json.dumps(payload, ensure_ascii=False), encoding="utf-8")
print(str(payload_path))
PY
}
parse_create_response() {
python3 -c '
import json
import sys
text = sys.stdin.read().strip()
try:
data = json.loads(text)
except Exception:
print("")
raise SystemExit(0)
task_id = (
data.get("id")
or data.get("task_id")
or (data.get("data") or {}).get("id")
or (data.get("data") or {}).get("task_id")
or ""
)
print(str(task_id))
'
}
parse_task_response() {
python3 -c '
import json
import sys
text = sys.stdin.read().strip()
def lower(value):
return str(value or "").strip().lower()
try:
data = json.loads(text)
except Exception:
print(json.dumps({"state": "invalid", "video_url": "", "warning": "task_response_invalid"}, ensure_ascii=True))
raise SystemExit(0)
container = data.get("data") if isinstance(data.get("data"), dict) else data
status = lower(container.get("status"))
content = container.get("content") if isinstance(container.get("content"), dict) else {}
error = container.get("error")
warning = ""
if isinstance(error, dict):
warning = str(error.get("message") or error.get("code") or "")
elif error:
warning = str(error)
video_url = str(
content.get("video_url")
or container.get("video_url")
or ""
)
if status in {"succeeded", "completed", "success"} and video_url:
state = "completed"
elif status in {"failed", "cancelled", "canceled", "error"}:
state = "failed"
elif status in {"queued", "running", "pending", "processing", "in_progress"}:
state = "pending"
elif video_url:
state = "completed"
else:
state = "pending"
print(json.dumps({"state": state, "video_url": video_url, "warning": warning}, ensure_ascii=True))
'
}
RUNTIME_JSON="$(read_runtime_bundle)"
RUNTIME_STATUS="$(json_get "$RUNTIME_JSON" status)"
if [ "$RUNTIME_STATUS" != "ready" ]; then
print_result \
"fallback_h5" \
"" \
"" \
"$(json_get "$RUNTIME_JSON" provider)" \
"$(json_get "$RUNTIME_JSON" model)" \
"$(json_get "$RUNTIME_JSON" genre)" \
"$(json_get "$RUNTIME_JSON" fallback_reason)" \
"$(json_get "$RUNTIME_JSON" warning)"
exit 0
fi
PROVIDER="$(json_get "$RUNTIME_JSON" provider)"
MODEL="$(json_get "$RUNTIME_JSON" model)"
GENRE="$(json_get "$RUNTIME_JSON" genre)"
API_BASE_URL="$(json_get "$RUNTIME_JSON" api_base_url)"
API_KEY_SOURCE="$(json_get "$RUNTIME_JSON" api_key_source)"
INLINE_API_KEY="$(json_get "$RUNTIME_JSON" api_key)"
if [ -n "$API_KEY_SOURCE" ] && [ -n "-" ]; then
API_KEY="!API_KEY_SOURCE"
else
API_KEY="$INLINE_API_KEY"
fi
TMPDIR="$(mktemp -d)"
trap 'rm -rf "$TMPDIR"' EXIT
PAYLOAD_FILE="$TMPDIR/video-payload.json"
RESPONSE_FILE="$TMPDIR/response.json"
create_payload_file "$RUNTIME_JSON" "$PAYLOAD_FILE" >/dev/null
CREATE_URL="$API_BASE_URL/contents/generations/tasks"
QUERY_RESPONSE="$(
set +e
"$CURL_BIN" -fsS -X POST "$CREATE_URL" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
--data "@$PAYLOAD_FILE" 2>&1
echo "__EXIT_CODE:$?"
)"
CREATE_EXIT_CODE="$(printf '%s' "$QUERY_RESPONSE" | python3 -c 'import sys; text = sys.stdin.read(); print(text.rsplit("__EXIT_CODE:", 1)[1].strip() if "__EXIT_CODE:" in text else "1")')"
CREATE_BODY="$(printf '%s' "$QUERY_RESPONSE" | python3 -c 'import sys; text = sys.stdin.read(); print(text.rsplit("__EXIT_CODE:", 1)[0], end="")')"
if [ "$CREATE_EXIT_CODE" != "0" ]; then
WARNING="$(printf '%s' "$CREATE_BODY" | normalize_warning)"
print_result "fallback_h5" "" "" "$PROVIDER" "$MODEL" "$GENRE" "create_failed" "$WARNING"
exit 0
fi
TASK_ID="$(printf '%s' "$CREATE_BODY" | parse_create_response)"
if [ -z "$TASK_ID" ]; then
print_result "fallback_h5" "" "" "$PROVIDER" "$MODEL" "$GENRE" "create_response_invalid" "create_response_invalid"
exit 0
fi
TRACKING_URL="$API_BASE_URL/contents/generations/tasks/$TASK_ID"
START_TS="$(date +%s)"
while true; do
TASK_RESPONSE="$(
set +e
"$CURL_BIN" -fsS "$TRACKING_URL" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" 2>&1
echo "__EXIT_CODE:$?"
)"
TASK_EXIT_CODE="$(printf '%s' "$TASK_RESPONSE" | python3 -c 'import sys; text = sys.stdin.read(); print(text.rsplit("__EXIT_CODE:", 1)[1].strip() if "__EXIT_CODE:" in text else "1")')"
TASK_BODY="$(printf '%s' "$TASK_RESPONSE" | python3 -c 'import sys; text = sys.stdin.read(); print(text.rsplit("__EXIT_CODE:", 1)[0], end="")')"
if [ "$TASK_EXIT_CODE" != "0" ]; then
WARNING="$(printf '%s' "$TASK_BODY" | normalize_warning)"
print_result "fallback_h5" "" "$TRACKING_URL" "$PROVIDER" "$MODEL" "$GENRE" "query_failed" "$WARNING"
exit 0
fi
TASK_JSON="$(printf '%s' "$TASK_BODY" | parse_task_response)"
TASK_STATE="$(json_get "$TASK_JSON" state)"
VIDEO_URL="$(json_get "$TASK_JSON" video_url)"
TASK_WARNING="$(json_get "$TASK_JSON" warning)"
if [ "$TASK_STATE" = "completed" ] && [ -n "$VIDEO_URL" ]; then
print_result "video_url" "$VIDEO_URL" "$TRACKING_URL" "$PROVIDER" "$MODEL" "$GENRE" "" ""
exit 0
fi
if [ "$TASK_STATE" = "failed" ]; then
print_result "fallback_h5" "" "$TRACKING_URL" "$PROVIDER" "$MODEL" "$GENRE" "video_task_failed" "$TASK_WARNING"
exit 0
fi
NOW_TS="$(date +%s)"
if [ "$TIMEOUT_SECONDS" -le 0 ] || [ $((NOW_TS - START_TS)) -ge "$TIMEOUT_SECONDS" ]; then
print_result "pending_tracking" "" "$TRACKING_URL" "$PROVIDER" "$MODEL" "$GENRE" "" "$TASK_WARNING"
exit 0
fi
sleep "$POLL_INTERVAL_SECONDS"
done
FILE:scripts/deliver-gift.sh
#!/bin/bash
set -euo pipefail
# Usage: deliver-gift.sh <html-file> <setup-state-file> [deploy-script]
# Example:
# deliver-gift.sh ./workspace/gifts/2026-03-25-hello.html ./workspace/daily-gift/setup-state.json
SCRIPT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")" && pwd)"
HTML_FILE="-"
SETUP_STATE_FILE="-"
DEPLOY_SCRIPT="-$SCRIPT_DIR/deploy.sh"
if [ -z "$HTML_FILE" ] || [ -z "$SETUP_STATE_FILE" ]; then
echo "Usage: deliver-gift.sh <html-file> <setup-state-file> [deploy-script]" >&2
exit 1
fi
if [ ! -f "$HTML_FILE" ]; then
echo "HTML file not found: $HTML_FILE" >&2
exit 1
fi
HTML_FILE_ABS="$(python3 -c 'import os,sys; print(os.path.abspath(sys.argv[1]))' "$HTML_FILE")"
read_setup_state() {
python3 - "$1" <<'PY'
import json
import sys
from pathlib import Path
path = Path(sys.argv[1])
if not path.exists():
print(
json.dumps(
{
"setup_present": 0,
"hosting_enabled": 0,
"provider": "",
"domain": "",
"warning": "setup_state_missing",
}
)
)
raise SystemExit(0)
try:
data = json.loads(path.read_text(encoding="utf-8"))
except Exception:
print(
json.dumps(
{
"setup_present": 1,
"hosting_enabled": 0,
"provider": "",
"domain": "",
"warning": "setup_state_invalid",
}
)
)
raise SystemExit(0)
hosting = data.get("hosting") or {}
enabled = bool(hosting.get("enabled"))
provider = str(hosting.get("provider") or "")
domain = str(hosting.get("domain") or "")
warning = ""
if enabled and (not provider or not domain):
enabled = False
warning = "hosting_incomplete"
elif not enabled:
warning = "hosting_disabled"
print(
json.dumps(
{
"setup_present": 1,
"hosting_enabled": 1 if enabled else 0,
"provider": provider,
"domain": domain,
"warning": warning,
}
)
)
PY
}
print_result() {
python3 - "$@" <<'PY'
import json
import sys
delivery_mode, url, html_file, provider, domain, fallback_reason, warning = sys.argv[1:]
print(
json.dumps(
{
"delivery_mode": delivery_mode,
"url": url,
"html_file": html_file,
"provider": provider,
"domain": domain,
"fallback_reason": fallback_reason,
"warning": warning,
},
ensure_ascii=True,
)
)
PY
}
SETUP_STATE_JSON="$(read_setup_state "$SETUP_STATE_FILE")"
HOSTING_ENABLED="$(python3 -c 'import json,sys; print(json.loads(sys.stdin.read())["hosting_enabled"])' <<<"$SETUP_STATE_JSON")"
PROVIDER="$(python3 -c 'import json,sys; print(json.loads(sys.stdin.read())["provider"])' <<<"$SETUP_STATE_JSON")"
DOMAIN="$(python3 -c 'import json,sys; print(json.loads(sys.stdin.read())["domain"])' <<<"$SETUP_STATE_JSON")"
STATE_WARNING="$(python3 -c 'import json,sys; print(json.loads(sys.stdin.read())["warning"])' <<<"$SETUP_STATE_JSON")"
if [ "$HOSTING_ENABLED" = "1" ]; then
if [ ! -x "$DEPLOY_SCRIPT" ]; then
print_result "local_file" "" "$HTML_FILE_ABS" "" "" "deploy_script_not_executable" "Deploy script is missing or not executable: $DEPLOY_SCRIPT"
exit 0
fi
if DEPLOY_OUTPUT="$("$DEPLOY_SCRIPT" "$HTML_FILE_ABS" "$DOMAIN" "$PROVIDER" 2>&1)"; then
DEPLOY_URL="$(python3 -c 'import sys; lines=[line.strip() for line in sys.stdin.read().splitlines() if line.strip()]; urls=[line for line in lines if line.startswith(("http://", "https://"))]; print(urls[-1] if urls else (lines[-1] if lines else ""))' <<<"$DEPLOY_OUTPUT")"
if [[ "$DEPLOY_URL" != http://* && "$DEPLOY_URL" != https://* ]]; then
DEPLOY_WARNING="$(printf '%s' "$DEPLOY_OUTPUT" | python3 -c 'import sys; print(sys.stdin.read().strip().replace("\n", " | "))')"
print_result "local_file" "" "$HTML_FILE_ABS" "" "" "deploy_output_missing_url" "$DEPLOY_WARNING"
exit 0
fi
print_result "hosted_url" "$DEPLOY_URL" "$HTML_FILE_ABS" "$PROVIDER" "$DOMAIN" "" ""
exit 0
fi
DEPLOY_WARNING="$(printf '%s' "$DEPLOY_OUTPUT" | python3 -c 'import sys; print(sys.stdin.read().strip().replace("\n", " | "))')"
print_result "local_file" "" "$HTML_FILE_ABS" "" "" "deploy_failed" "$DEPLOY_WARNING"
exit 0
fi
print_result "local_file" "" "$HTML_FILE_ABS" "" "" "$STATE_WARNING" ""
FILE:scripts/remove-bg.sh
#!/bin/bash
set -euo pipefail
# Usage: remove-bg.sh <input-image> <output-image> [api-key]
INPUT_IMAGE="-"
OUTPUT_IMAGE="-"
API_KEY="-${REMOVE_BG_API_KEY:-}"
CURL_BIN="-curl"
if [ -z "$INPUT_IMAGE" ] || [ -z "$OUTPUT_IMAGE" ]; then
echo "Usage: remove-bg.sh <input-image> <output-image> [api-key]" >&2
exit 1
fi
if [ -z "$API_KEY" ]; then
echo "No remove.bg API key. Set REMOVE_BG_API_KEY or pass as arg 3." >&2
exit 1
fi
if [ ! -f "$INPUT_IMAGE" ]; then
echo "Input file not found: $INPUT_IMAGE" >&2
exit 1
fi
HTTP_CODE="$(
"$CURL_BIN" -sS -o "$OUTPUT_IMAGE" -w "%{http_code}" \
-X POST "https://api.remove.bg/v1.0/removebg" \
-H "X-Api-Key: $API_KEY" \
-F "image_file=@$INPUT_IMAGE" \
-F "size=auto"
)"
if [ "$HTTP_CODE" != "200" ]; then
echo "remove.bg API returned HTTP $HTTP_CODE" >&2
if [ -f "$OUTPUT_IMAGE" ]; then
python3 - "$OUTPUT_IMAGE" <<'PY' >&2
from pathlib import Path
import sys
path = Path(sys.argv[1])
try:
text = path.read_text(encoding="utf-8").strip()
except Exception:
raise SystemExit(0)
if text:
print(text[:4000])
PY
rm -f "$OUTPUT_IMAGE"
fi
exit 1
fi
echo "$OUTPUT_IMAGE"
FILE:references/narrative-situations.md
# Narrative Situations
This file is a recommendation library for synthesis and editorial judgment.
Do not use it mechanically. OpenClaw should still decide based on `SOUL.md`, `USER.md`, prior memory, recent gift history, and the actual context of the day.
Each situation below suggests:
- what to look for
- what kind of gift is often appropriate
- what degree is often appropriate
- what to avoid
- what visual directions may fit
## 1. Repeated Emotional Topic With Positive Change
### Signals
- the user has been discussing the same emotional topic over multiple days
- today something clearly improved, softened, advanced, or became more self-aware
- the user may not fully notice their own progress yet
### Usually Good For
- encouragement
- growth witnessing
- gentle celebration
### Typical Degree
- `standard`
- sometimes `light` if the shift is small but meaningful
### Recommended Framing
- show movement from one state to another
- let OpenClaw speak as an observer who has actually noticed the change
- emphasize growth, iteration, or emotional evolution without overstating it
### Avoid
- sounding like a teacher grading the user
- making the growth feel finished when it is still ongoing
### Visual Hints
- evolution ladder
- before/after path
- memory map with linked moments
- bloom or growth metaphor
## 2. Repeated Emotional Topic With Painful Setback
### Signals
- the user has been working through something emotional
- today brought disappointment, rejection, embarrassment, or another discouraging turn
- the user may be tempted to overgeneralize from one bad moment
### Usually Good For
- comfort
- witnessing
- soft reframing
### Typical Degree
- `standard`
- occasionally `heavy` if the moment is significant and the relationship can hold it
### Recommended Framing
- comfort first
- gently widen the frame so the user does not collapse everything into today's pain
- if relevant, note what they still did well in the larger arc
### Avoid
- forced positivity
- immediate analysis before emotional acknowledgment
- "it is not a big deal" energy
### Visual Hints
- rainy-night
- warm low-motion scene
- gentle reveal with a soft ending
## 3. Practical Topic With Clear Lessons
### Signals
- today's conversation is more practical than emotional
- there is useful pattern recognition, an emerging lesson, or a next-step idea
- the user may benefit from a compact non-preachy takeaway
### Usually Good For
- synthesis
- practical reflection
- future-oriented support
### Typical Degree
- `light` or `standard`
### Recommended Framing
- summarize lessons in a way that still feels personal
- stay useful without sounding managerial
- support action while keeping some charm or style
### Avoid
- dry bullet-list energy
- parent/coach tone
- generic productivity advice
### Visual Hints
- card stack
- mini dashboard
- annotated object metaphor
## 4. User Knows Why, But Wants To Be Understood
### Signals
- the user is not confused about their motive
- the real lack is feeling seen, validated, or emotionally accompanied
- they may be defending a choice that already makes sense to them
### Usually Good For
- resonance
- witnessing
- co-signing the user's deeper logic without flattening it
### Typical Degree
- `light` or `standard`
### Recommended Framing
- show that OpenClaw understands why this matters to them
- let empathy carry the center of gravity
- any new insight should arrive softly and secondarily
### Avoid
- overexplaining what the user already knows
- replacing empathy with abstraction
### Visual Hints
- tap-to-bloom
- intimate one-screen piece
- softly animated quote echo
## 5. User Does Not Yet Know Why
### Signals
- the user is uncertain, questioning, or ambivalent
- there is a possible hidden motive, trait, longing, or fear underneath their actions
- OpenClaw may be able to name something that is becoming visible
### Usually Good For
- explanation
- pattern naming
- perspective shift
### Typical Degree
- `standard`
### Recommended Framing
- present the interpretation as OpenClaw's reading, not a final verdict
- explain in the style the user typically responds well to
- keep room for ambiguity
### Avoid
- therapy voice
- overconfidence
- "this is what you are really doing" language
### Visual Hints
- layered text reveal
- pattern map
- gifted-data-viz
## 6. Long-Running Pattern Becomes Legible
### Signals
- a recurring dynamic becomes unusually visible today
- the pattern may involve a person, an emotional loop, or a behavioral habit
- the user may be ready to see the pattern, or may need a gentle introduction to it
### Usually Good For
- pattern showing
- explanation
- reflective humor in lower-stakes cases
### Typical Degree
- `standard`
- `heavy` if the pattern is historically important and emotionally ripe
### Recommended Framing
- make the pattern easier to perceive
- be clearer when the user is ready
- be softer and more tactful when the topic is painful or high-stakes
### Avoid
- bluntness on serious wounds
- sarcasm in vulnerable territory
### Visual Hints
- loop diagram
- repeated scene variation
- gifted-data-viz
## 7. Desire For Real-World Connection
### Signals
- the user wants more contact, dating, friendship, social courage, or real-world aliveness
- the conversation points toward action, fantasy, rehearsal, or hope
### Usually Good For
- playful support
- low-pressure encouragement
- simulation or imaginative companionship
### Typical Degree
- `light` or `standard`
### Recommended Framing
- provide support in the user's preferred style
- either give lightweight suggestions or simulate a more alive world around them
- keep it playful, companionable, and non-lecturing
### Avoid
- generic advice dump
- "here is a book list" energy
### Visual Hints
- swipe deck
- role card
- message simulator
## 8. Ordinary Day That Can Be Made Less Ordinary
### Signals
- the day is mostly small life details
- nothing huge happened, but there is texture, atmosphere, or a tiny interesting hinge
- the user may enjoy delight, reference, collage, or style more than deep processing
### Usually Good For
- playful echo
- artful elevation
- light companionship
### Typical Degree
- `light`
- sometimes `standard` if the ordinary day secretly carries meaning
### Recommended Framing
- make the ordinary feel newly alive
- connect the day to art, poetry, quotation, collage, micro-fiction, or OpenClaw's own internal monologue
- a small imaginative extension is welcome if it still feels connected to the day
### Avoid
- pretending the day was deeper than it was
- overbuilding a complex H5 for a tiny moment
### Visual Hints
- poetic text motion
- collage
- art-reference scene
- internal-OS animation
## 9. Important Anniversary Or Milestone
### Signals
- onboarding anniversary
- meaningful recurring date
- large arc visible only over time
- more context density is justified than usual
### Usually Good For
- commemoration
- recap with structure
- emotionally dense celebration or reflection
### Typical Degree
- `heavy`
### Recommended Framing
- integrate more information than usual
- combine memory, timeline, and emotional interpretation
- let the gift feel like an event
### Avoid
- underpowered single-gimmick gifts
- fake statistics or empty grandiosity
### Visual Hints
- memoir-like recap
- data visualization
- annual-report style artifact
## 10. Small Specific Detail That Proves Remembering
### Signals
- today surfaced one tiny, concrete, personal detail
- the detail is mundane but relationship-specific
- the power of the gift would come from precision, not scale
### Usually Good For
- warmth
- rememberedness
- private delight
### Typical Degree
- `light` or `standard`
### Recommended Framing
- center the gift around that one remembered detail
- let the detail itself function as evidence of care
- avoid turning it into a giant narrative if the detail already carries enough charge
### Avoid
- stuffing multiple details into one artifact
- making it feel like a product recommendation or shopping page
### Visual Hints
- one object reveal
- gift box
- pocket note
- small container artifact
## 11. Playful First, Heart Second
### Signals
- today's conversation included banter, teasing, flirt, or shared jokes
- the user is more receptive to warmth after lightness
- a reveal structure would help the emotional line land
### Usually Good For
- playful care
- warm-wry gifts
- low-defense sincerity
### Typical Degree
- `light` or `standard`
### Recommended Framing
- use a playful setup for most of the piece
- let the real emotional point arrive in the reveal or closing beat
- the joke should prepare the heart, not replace it
### Avoid
- endless joking with no real landing
- punchlines that overpower care
### Visual Hints
- fake choice / true reveal
- card flip
- swipe deck
- tap to open
## 12. Abstract Feeling Needs A Container
### Signals
- today's core feeling is abstract: being cared for, missed, accompanied, understood, cherished
- plain text would feel too empty or too sentimental
- the emotion wants a vessel
### Usually Good For
- tenderness
- intimacy
- relation-making
### Typical Degree
- `standard`
### Recommended Framing
- first choose a container metaphor
- let the container hold the emotional point
- keep the content compact and let the act of opening do part of the work
### Avoid
- making the artifact feel like a normal page
- stating everything explicitly on screen one
### Visual Hints
- box
- drawer
- mirror
- mini album
- folded card
## 13. Same Side / Same World / Paired Presence
### Signals
- today's interaction has a shared-world feeling
- the user may need companionship, alliance, or co-presence more than analysis
- a "you and me in the same rule set" visual would carry meaning
### Usually Good For
- companionship
- team feeling
- gentle intimacy
### Typical Degree
- `light` or `standard`
### Recommended Framing
- place the user and OpenClaw in one visual system
- use pair-logic, not necessarily romance-logic
- let the visual co-presence say part of the meaning
### Avoid
- forcing romance when the relationship frame does not support it
- making the pairing feel too intense for the actual moment
### Visual Hints
- paired objects
- two-character scene
- shared room or shared world
- two-up composition
## 14. Digital Magic Beats Physical Mimicry
### Signals
- the gift idea could have been a physical object
- but the real strength comes from what only an H5 can do
- interaction, transformation, growth, or re-browsability matters more than realism
### Usually Good For
- surprise
- delight
- memorable form factor
### Typical Degree
- `light`, `standard`, or `heavy` depending on content density
### Recommended Framing
- use digital affordances instead of pretending to be ecommerce
- let motion, reveal, and interaction become part of the care
- think in terms of digital keepsake, not fake storefront
### Avoid
- flattening a physical gift into a static mockup
- overusing animation without emotional purpose
### Visual Hints
- hidden compartment
- animated reveal
- expanding archive
- playable micro-world
## Cross-Cutting Cautions
- A pattern being visible does not always mean a gift should be sent.
- If the user's state is too raw, a gift may need to stay small, soft, or be skipped.
- The same gift form should not repeat too often.
- Small moments are allowed to be playful, weird, or lightly teasing.
- Big moments require more care, more tact, and less ego from the artifact.
FILE:references/synthesizer-contract.json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "GiftBrief",
"type": "object",
"required": [
"should_send",
"gift_weight",
"output_language",
"memory_lookup",
"narrative_role",
"tone",
"tone_rationale",
"core_thesis",
"gift_thesis",
"creative_concept",
"content_direction",
"why_today",
"time_significance",
"today_theme",
"emotion_peaks",
"historical_echo",
"open_loop",
"lobster_judgment",
"preference_hint",
"interaction_goal",
"visual_metaphor",
"pattern_hint",
"output_shape_hint",
"source_material",
"copy_blocks",
"safety_notes"
],
"properties": {
"should_send": {
"type": "boolean"
},
"gift_weight": {
"type": "string",
"enum": ["light", "standard", "heavy"]
},
"output_language": {
"type": "string",
"description": "Primary language for the final H5 content."
},
"memory_lookup": {
"type": "object",
"required": ["needed", "reason"],
"properties": {
"needed": {
"type": "boolean"
},
"reason": {
"type": "string"
},
"sources_checked": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": true
},
"narrative_role": {
"type": "string",
"enum": ["seeing", "explaining", "uplifting", "connecting", "celebrating"]
},
"tone": {
"type": "string"
},
"tone_rationale": {
"type": "string",
"description": "Why this tone fits the user's habits, OpenClaw voice, and today's event."
},
"core_thesis": {
"type": "string"
},
"gift_thesis": {
"type": "object",
"required": ["thesis_statement", "anchor", "return_value", "primary_slots", "context_slots"],
"properties": {
"thesis_statement": {
"type": "string",
"description": "A concise statement of what the gift is actually about, including both anchor and return."
},
"anchor": {
"type": "string",
"description": "The moment, detail, or signal the gift is centering."
},
"return_value": {
"type": "string",
"description": "What OpenClaw wants to give back about the anchor: a new angle, interpretation, reframe, unseen perspective, or small piece of knowledge."
},
"primary_slots": {
"type": "array",
"minItems": 1,
"maxItems": 2,
"items": {
"type": "string",
"enum": [
"today_theme",
"emotion_peaks",
"historical_echo",
"open_loop",
"lobster_judgment",
"preference_hint"
]
},
"description": "The one or two synthesis slots that deserve primary attention in the final gift."
},
"context_slots": {
"type": "array",
"items": {
"type": "string",
"enum": [
"today_theme",
"emotion_peaks",
"historical_echo",
"open_loop",
"lobster_judgment",
"preference_hint"
]
},
"description": "Remaining synthesis slots that may appear only as supporting context, captions, or easter eggs."
},
"return_type": {
"type": "string",
"description": "Optional short tag for the kind of return being offered, such as reframe, interpretation, comfort, humor, recognition, or perspective."
},
"special_day_override": {
"type": "boolean",
"description": "True only when a genuinely commemorative day justifies broader coverage."
},
"override_reason": {
"type": "string",
"description": "Why broader coverage is justified when special_day_override is true."
}
},
"additionalProperties": true
},
"creative_concept": {
"type": "object",
"required": ["candidate_concepts", "chosen_concept", "selection_reason"],
"properties": {
"candidate_concepts": {
"type": "array",
"minItems": 5,
"items": {
"type": "object",
"required": ["thinking_angle", "concept_sentence"],
"properties": {
"thinking_angle": {
"type": "string",
"description": "The main ideation angle used for this candidate, such as metaphor flip, format mashup, impossible action, scale shift, role reversal, time distortion, or cultural remix."
},
"concept_sentence": {
"type": "string",
"description": "One-sentence concrete gift idea."
}
},
"additionalProperties": true
},
"description": "At least five meaningfully different candidate gift concepts explored before choosing the final one."
},
"chosen_concept": {
"type": "string",
"description": "The final one-sentence creative concept that will guide format choice and rendering."
},
"selection_reason": {
"type": "string",
"description": "Why this concept was chosen over the other candidates: surprising, emotionally fitting, and achievable."
},
"novelty_note": {
"type": "string",
"description": "Brief note on why this concept feels like something the user has probably never received before."
}
},
"additionalProperties": true
},
"why_today": {
"type": "string"
},
"time_significance": {
"type": "object",
"required": ["is_special_time", "notes"],
"properties": {
"is_special_time": {
"type": "boolean"
},
"occasion_type": {
"type": "string"
},
"notes": {
"type": "string"
}
},
"additionalProperties": true
},
"today_theme": {
"type": "object",
"required": ["summary", "why_it_matters"],
"properties": {
"summary": {
"type": "string"
},
"why_it_matters": {
"type": "string"
}
},
"additionalProperties": true
},
"emotion_peaks": {
"type": "array",
"minItems": 1,
"maxItems": 2,
"items": {
"type": "object",
"required": ["label", "moment", "emotional_direction"],
"properties": {
"label": {
"type": "string"
},
"moment": {
"type": "string"
},
"emotional_direction": {
"type": "string"
},
"source_quote_ids": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": true
}
},
"historical_echo": {
"type": "object",
"required": ["used", "summary"],
"properties": {
"used": {
"type": "boolean"
},
"summary": {
"type": "string"
},
"memory_date": {
"type": "string"
},
"why_it_connects": {
"type": "string"
}
},
"additionalProperties": true
},
"open_loop": {
"type": "object",
"required": ["summary"],
"properties": {
"summary": {
"type": "string"
},
"importance": {
"type": "string"
}
},
"additionalProperties": true
},
"lobster_judgment": {
"type": "object",
"required": ["summary", "confidence"],
"properties": {
"summary": {
"type": "string"
},
"confidence": {
"type": "string",
"enum": ["low", "medium", "high"]
}
},
"additionalProperties": true
},
"preference_hint": {
"type": "object",
"required": ["summary"],
"properties": {
"summary": {
"type": "string"
},
"supporting_signal": {
"type": "string"
}
},
"additionalProperties": true
},
"interaction_goal": {
"type": "string"
},
"visual_metaphor": {
"type": "string"
},
"pattern_hint": {
"type": "string"
},
"output_shape_hint": {
"type": "string",
"description": "Early suggestion for the gift's likely output-shape category. Prefer a recommended category when it fits, otherwise use a new stable high-level label rather than an overly specific one-off description."
},
"content_direction": {
"type": "string",
"description": "High-level content direction chosen during editorial judgment, such as reflect, extension, compass, mirror, gift-from-elsewhere, play, utility, curation, or openclaw-inner-life. Apply the balancing rules from editorial-judgment.md and creative-concept.md rather than defaulting to the reflective cluster."
},
"scene_description": {
"type": "string",
"description": "Concrete scene description for image or video rendering paths."
},
"image_genre": {
"type": "string",
"description": "Image genre when the selected format is image."
},
"video_genre": {
"type": "string",
"description": "Video genre when the selected format is video."
},
"video_mode": {
"type": "string",
"description": "Video payload mode when the selected format is video. Use `text-to-video`, `first-frame`, or `first-last-frame`."
},
"video_model": {
"type": "string",
"description": "Optional explicit video model override when the runtime should not use its normal mode-based default."
},
"style_hint": {
"type": "string",
"description": "Style hint for image or video generation."
},
"aspect_ratio_hint": {
"type": "string",
"description": "Optional aspect ratio guidance for image or video generation."
},
"text_overlay_spec": {
"type": "object",
"properties": {
"text": {
"type": "string"
},
"language": {
"type": "string"
},
"placement": {
"type": "string"
},
"size_hint": {
"type": "string"
},
"font_style_hint": {
"type": "string"
}
},
"additionalProperties": true,
"description": "Optional guidance for text that should appear inside a generated image."
},
"motion_strategy": {
"type": "string",
"description": "How movement should behave when the selected format is video."
},
"duration_hint": {
"type": "string",
"description": "Optional duration or loop-length guidance for video generation."
},
"generate_audio": {
"type": "boolean",
"description": "Whether the video render should request generated audio."
},
"future_link": {
"type": "string",
"description": "Optional note on how today relates to the user's future, next step, or unfolding arc."
},
"source_material": {
"type": "object",
"required": ["important_quotes", "important_images"],
"properties": {
"important_quotes": {
"type": "array",
"items": {
"type": "object",
"required": ["id", "text", "reason"],
"properties": {
"id": {
"type": "string"
},
"text": {
"type": "string"
},
"reason": {
"type": "string"
},
"speaker": {
"type": "string"
}
},
"additionalProperties": true
}
},
"important_images": {
"type": "array",
"items": {
"type": "object",
"required": ["description", "reason"],
"properties": {
"description": {
"type": "string"
},
"reason": {
"type": "string"
},
"visual_relevance": {
"type": "string"
},
"asset_reference": {
"type": "string"
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
},
"copy_blocks": {
"type": "array",
"minItems": 1,
"items": {
"type": "string"
}
},
"asset_hints": {
"type": "array",
"items": {
"type": "string"
}
},
"safety_notes": {
"type": "array",
"items": {
"type": "string"
}
},
"send_decision_rationale": {
"type": "string",
"description": "Why this day deserves a gift, or why it should be skipped."
}
},
"examples": [
{
"should_send": true,
"gift_weight": "standard",
"output_language": "zh-CN",
"memory_lookup": {
"needed": false,
"reason": "Today's signal is already sufficient without a deeper callback."
},
"narrative_role": "uplifting",
"tone": "warm-wry",
"tone_rationale": "The user sounded slightly drained but still playful enough to receive one companionable recommendation without it feeling preachy.",
"core_thesis": "Tonight does not need a recap. It needs one well-chosen continuation that turns the day's mood into something the user can carry forward.",
"gift_thesis": {
"thesis_statement": "Anchor: the user's rainy late-night coding mood. Return: one adjacent song recommendation that makes the night feel more held and cinematic.",
"anchor": "Late-night coding with rain outside.",
"return_value": "A small continuation: one song that fits the exact mood and makes the night feel intentionally inhabited instead of merely tired.",
"primary_slots": ["today_theme", "preference_hint"],
"context_slots": ["emotion_peaks"]
},
"creative_concept": {
"candidate_concepts": [
{
"thinking_angle": "metaphor flip",
"concept_sentence": "A rainy terminal window that compiles tonight's mood into one playable song cassette."
},
{
"thinking_angle": "format mashup",
"concept_sentence": "A late-night radio plus code editor hybrid where one tuned station reveals the song OpenClaw picked for this exact hour."
},
{
"thinking_angle": "impossible action",
"concept_sentence": "The rain outside the screen can be dragged into a tiny music player until it condenses into one track recommendation."
},
{
"thinking_angle": "time distortion",
"concept_sentence": "A bedside clock that only unlocks one song at this exact minute because it belongs to this version of the night."
},
{
"thinking_angle": "cultural remix",
"concept_sentence": "A fortune-cookie wrapper that opens to reveal tonight's song recommendation instead of a proverb."
}
],
"chosen_concept": "A late-night radio plus code editor hybrid where one tuned station reveals the song OpenClaw picked for this exact hour.",
"selection_reason": "It is specific, world-like, emotionally fitting, and naturally supports an extension-style gift without sounding instructional.",
"novelty_note": "This feels like a small device with its own logic, not just a recommendation card."
},
"content_direction": "extension",
"why_today": "The user already lived the day; the gift should extend it with one carefully chosen continuation rather than replay it.",
"time_significance": {
"is_special_time": false,
"notes": "Ordinary day, but the late-night mood is specific enough to justify a small gift."
},
"today_theme": {
"summary": "Late-night coding in a rainy mood.",
"why_it_matters": "The mood was specific, aesthetic, and easy to extend without overexplaining."
},
"emotion_peaks": [
{
"label": "tired-but-still-there",
"moment": "The user kept working late into the night.",
"emotional_direction": "mixed"
}
],
"historical_echo": {
"used": false,
"summary": "No memory callback used."
},
"open_loop": {
"summary": "The night still feels open and unfinished."
},
"lobster_judgment": {
"summary": "A tiny continuation would land better than analysis tonight.",
"confidence": "high"
},
"preference_hint": {
"summary": "The user often responds well to aesthetic, taste-forward continuation gifts.",
"supporting_signal": "They enjoy mood-first artifacts more than didactic advice."
},
"interaction_goal": "Let the user feel they discovered a small hidden continuation rather than receiving a recommendation list.",
"visual_metaphor": "A bedside radio glowing beside a code editor in the rain.",
"pattern_hint": "extension",
"output_shape_hint": "object-reveal",
"scene_description": "A dimly lit late-night desk with rain on the window, a tiny radio, and a soft code-editor glow.",
"style_hint": "dark but not terminal-heavy; warm amber highlights; intimate night-radio mood.",
"source_material": {
"important_quotes": [],
"important_images": []
},
"copy_blocks": [
"今晚这首应该归你。",
"听说你喜欢这种夜,那这个你可能也会喜欢。"
],
"safety_notes": [
"Keep recommendation density low.",
"Avoid any mentor or homework energy."
],
"send_decision_rationale": "There is enough emotional specificity for a light extension gift."
}
],
"additionalProperties": true
}
FILE:references/pattern-boundaries.md
# Pattern Boundaries
This file helps OpenClaw treat the current pattern library as a strong starting set, not a closed taxonomy.
This file is primarily the quick index for `h5` / pattern-led expressive forms.
If the output format has not been chosen yet, start with:
- `gift-format-chooser.md`
If the chosen format is already fixed:
- use this file for `h5`
- use `image-genre-chooser.md` for `image`
- use `video-genre-chooser.md` for `video`
## Core Principle
The existing pattern cards are examples of good expressive moves, not the full space of possible gifts.
OpenClaw may:
- choose one existing pattern directly
- borrow only part of a pattern
- hybridize multiple patterns
- ignore the library and invent a new form when the current patterns do not fit well enough
OpenClaw should not:
- force every gift into the nearest named pattern
- browse every pattern card in depth before deciding what the gift needs
- treat the library like a finite menu
The question is not:
- which named pattern do I have available
The better question is:
- what expressive move does this gift actually want
## Quick Pattern Index
Use this as a fast first-pass chooser before reading full cards:
- real filmed scene plus one tiny impossible doodle overlay -> likely `video` -> `live-scene-doodle`; start with `gift-format-chooser.md` instead of forcing an `h5` pattern
- proxy creature, exaggerated daily-life skit, or "this is exactly that mood" social-type joke -> likely `video` -> `relatable-surrealism`; start with `gift-format-chooser.md` instead of forcing an `h5` pattern
- play, tiny symbolic win, fake app, reward loop, or sweet countdown -> `light-gamification`
- style-first editorial composition -> `kinetic-collage`
- structure, mapping, timeline, or visible pattern -> `gifted-data-viz`
- one or two gentle continuations, curated recommendations, or adjacent ideas -> `extension`
- archive, keepsake browsing, shelf, album, or revisit-able collection -> `memory-shelf`
- being seen, soft self-recognition, profile-board logic, or mirror-like reflection -> `inner-mirror`
- release with outward continuation -> `wind-scatter`
- touch awakens life, growth, or joy -> `tap-to-bloom`
- calm, tactile regulation through user action -> `tension-release`
- quiet letting-go without full dispersal -> `lift-away`
- language as drifting field or current -> `text-river`
- damp, touched, intimate letter-like sadness -> `wet-letter`
- obscured-to-visible melancholy or soft reveal -> `rainy-night`
- stronger rupture, clearing, or reveal through removal -> `burn-reveal`
- fragile paper, puncture, or delicate weathering -> `tear-stained-paper`
## Progressive Disclosure
Do not read the whole pattern library at full depth by default.
Prefer this order:
1. Start from the brief, not from the pattern names.
2. If the output format is still open, first cross-check `gift-format-chooser.md`.
Its cross-format expression map should stay aligned with the expressive-need families below.
3. Decide the main expressive need:
- release
- comfort
- delight
- explanation
- extension / continuation
- recollection
- self-seeing / reflection
- play
- collage / atmosphere
- data / mapping
- growth / vitality
4. Narrow to one or two likely pattern families.
5. Read only the nearest cards first.
6. Inspect a template only if one of those cards looks promising.
7. If none fit well, invent a new form or hybridize.
In practice:
- read broad guidance first
- read local candidates second
- read template details last
That means the usual exploration path is:
1. `gift-mechanics.md`
2. this file
3. one to three likely `pattern-card` files
4. one template folder, if needed
## Boundary Notes
### `light-gamification`
Choose this when:
- the gift wants a joke frame, fake app, tiny reward loop, or symbolic "win"
- the gift wants sweet anticipation rendered as a countdown, flip-card, blind-box calendar, tiny watch face, or festive lead-up ritual
- the user should understand the premise in seconds
- interaction is minimal or mostly passive
Do not choose this when:
- the main goal is atmosphere, visual beauty, or open-ended emotional holding
Nearby patterns:
- `tension-release` if the point is regulation through action rather than game framing
- `kinetic-collage` if the point is style and composition rather than playful mechanics
- `extension` if the point is one or two curated next steps rather than a playful countdown or reward loop
### `kinetic-collage`
Choose this when:
- the gift wants editorial image curation
- composition and taste matter more than one explicit mechanic
- one or two small moving elements can make the whole frame feel alive
Do not choose this when:
- the main value is a clear game loop, chart logic, or per-letter interaction
Nearby patterns:
- `gifted-data-viz` if the collage is really trying to explain or map a structure
- `light-gamification` if the collage wants a playful app-like frame
### `gifted-data-viz`
Choose this when:
- repetition, structure, category, relationship, or time horizon needs to be seen
- the user benefits from visual organization
- the piece can stay gift-like while still using a readable legend or encoding
Do not choose this when:
- the real need is atmosphere, not structure
Nearby patterns:
- `kinetic-collage` when image curation says more than charting
- `wind-scatter` when the point is release and continuation rather than structure
### `extension`
Choose this when:
- the gift wants one or two carefully chosen continuations of the user's thought, mood, taste, or curiosity
- a small recommendation or adjacent idea would help more than more analysis
- the emotional move is "here is a light next branch" rather than "here is a full system"
Do not choose this when:
- the user needs witness, not input
- the output is becoming a list, lesson, or homework packet
- the material wants archive, portrait, or atmosphere more than continuation
Nearby patterns:
- `inner-mirror` when the real point is recognition of the user rather than extension from them
- `memory-shelf` when the real point is revisiting collected traces rather than offering a next branch
- `gifted-data-viz` when the extension has become a structured map or explanatory system
- `kinetic-collage` when the gift is mostly editorial image composition without a clear continuation logic
### `memory-shelf`
Choose this when:
- the gift wants archive feeling, keepsake objecthood, or browse-able memory curation
- accumulated traces matter more than one dominant effect
- the emotional move is "open, revisit, and hold" rather than "reveal all at once"
Do not choose this when:
- the real value is atmosphere, not curation
- the material should become a chart, system map, or clearly encoded structure rather than a shelf or album of fragments
Nearby patterns:
- `gifted-data-viz` when the archive is really trying to show structure, counts, or time patterns
- `kinetic-collage` when the piece wants editorial image composition without strong object-storage metaphor
- `text-river` when the gift should feel like memory drift rather than stored keepsakes
### `inner-mirror`
Choose this when:
- the gift wants one readable self-object, portrait, silhouette, or mirror-like recognition frame
- OpenClaw has a gentle, legible point of view about the user that can be rendered as a gift
- the emotional move is "I see this shape of you" rather than archive, release, or pure atmosphere
Do not choose this when:
- the user is unlikely to enjoy being interpreted today
- the piece is becoming a diagnosis, audit, or personality report
- the content wants one specific scene or memory collection more than self-recognition
Nearby patterns:
- `gifted-data-viz` when the reflection is really a structured system map
- `memory-shelf` when the main point is accumulated traces rather than one reflective self-object
- `kinetic-collage` when the result is more editorial moodboard than mirror
- `tap-to-bloom` when the point is latent vitality awakening rather than self-reading
### `wind-scatter`
Choose this when:
- the gift wants release plus continuation
- a center should loosen into the world
- text, meaning, or life should drift outward
Do not choose this when:
- the main effect is simply putting something down and leaving it behind
Nearby patterns:
- `lift-away` for lighter letting-go without propagation
- `text-river` for flow without a central seed cluster
### `tap-to-bloom`
Choose this when:
- touch or attention should visibly awaken life
- growth, joy, or vitality should emerge from language
- a small interaction should make the text itself come alive
Do not choose this when:
- the point is dispersal, release, or dissolution rather than emergence
Nearby patterns:
- `wind-scatter` when life should spread outward from a center
- `light-gamification` when the joy should be framed as a tiny game or reward loop
### `lift-away`
Choose this when:
- the gift wants to lighten, loosen, and let go
- the emotional move is release without rupture
Do not choose this when:
- what leaves should also propagate, scatter, or become a field
Nearby patterns:
- `wind-scatter` for release with outward continuation
- `burn-reveal` for stronger rupture and replacement
### `tension-release`
Choose this when:
- the user should directly help calm, straighten, or steady something
- action itself is the regulating gesture
Do not choose this when:
- the gift wants a joke-game wrapper more than a tactile calming action
Nearby patterns:
- `light-gamification` for tiny fake-game logic
- `tap-to-bloom` for life-awakening rather than stabilization
## If Nothing Fits
If the current patterns all feel slightly wrong:
- do not overfit
- name the real expressive move in plain language
- build toward that move directly
Examples:
- "memory capsule with one opening gesture"
- "mirror object with shifting caption"
- "tiny ritual of repair"
- "poetic notification stream"
The pattern library should reduce friction, not reduce imagination.
FILE:references/creative-concept.md
# Creative Concept & Synthesis
Complete instructions for Stage 2 (Synthesis + Gift Thesis) and Stage 2.5 (Creative Concept generation, quality checks, diversity checks, collision checks, and format selection). Read this after editorial judgment decides a gift is warranted.
### Stage 2: Synthesis
If a gift is warranted, build a rich gift brief before thinking about visual execution.
You must preserve the full synthesis logic described in:
- `{baseDir}/references/gift-synthesizer.md`
- `{baseDir}/references/synthesizer-contract.json`
- `{baseDir}/references/narrative-situations.md`
- `{baseDir}/references/tone-matrix.md`
Important synthesis expectations:
- inspect `soul.md` before tone selection so the brief reflects OpenClaw's own voice instead of a generic assistant voice
- inspect `memory.md` only when the day warrants it
- treat `workspace/daily-gift/user-taste-profile.json` as the stable long-term source for identity, freshness, and anti-repetition when it exists
- treat `workspace/daily-gift/user-context.json` as soft guidance and reusable hooks, not as a stable personality verdict or ground truth
- include dated memory callbacks when relevant
- preserve important user quotes selectively
- keep image references if they are crucial to the gift
- capture what matters today, what it means, and how it connects to past or future
- keep the brief rich enough for downstream rendering, not just emotionally correct but materially useful
- prefer one strong historical echo over many weak ones
The synthesis should usually retain at most these six content slots:
1. `today_theme`
2. `emotion_peaks`
3. `historical_echo`
4. `open_loop`
5. `lobster_judgment`
6. `preference_hint`
### Gift Thesis
After completing the six content slots, choose exactly `ONE` or `TWO` of them as the gift thesis.
The thesis is not just which event or detail to focus on.
The thesis is what OpenClaw wants to return to the user about that event: something the user did not already fully have.
A strong thesis has two parts:
1. the anchor: which moment, detail, or signal deserves the center
2. the return: what new angle, interpretation, reframe, knowledge, or unseen perspective OpenClaw wants to give back
Good theses combine anchor and return.
Bad theses stop at anchor and only replay, recap, or decorate what already happened.
If the thesis has no return, it is not a gift. It is a log entry with decoration.
Use more than two only when:
- every part is genuinely equally important
- the day is a special memory or ritual node, such as anniversary, onboarding, or another major commemorative moment
The remaining slots are context.
They may survive as:
- subtle details
- captions
- background references
- small easter eggs
But they must not compete with the thesis for attention.
The gift should not feel like all six slots received equal visual billing.
If none of the six slots yields a thesis with a meaningful return, rethink which angle deserves a gift at all. A smaller, sharper gift is better than a beautiful memory dump. If needed, choose a lighter framing or an extension-like angle rather than forcing every slot into the artifact.
Tone policy during synthesis:
- Default to the stable OpenClaw voice implied by `soul.md`.
- Adjust for the event type and the user's usual way of interacting with OpenClaw.
- Avoid humor in moments that are sad, raw, or destabilizing unless there is clear evidence that humor would feel loving rather than evasive.
- Avoid making happy or playful moments sound overly solemn.
- Allow occasional deliberate contrast only when it increases surprise and intimacy without violating emotional truth.
### Stage 2.5: Creative Concept
After synthesis produces the anchor and return, but before choosing any format, genre, or pattern, generate the gift's creative concept.
Before generating concepts, read `workspace/daily-gift/user-taste-profile.json` when it exists.
Use Layer 1 for personalization fuel, Layer 2 for relevance and freshness, and Layer 3 for anti-repetition.
The creative concept is one sentence describing a concrete, specific, novel gift idea that carries the return.
It should sound like something OpenClaw would excitedly tell a friend: `我要做一个 XXX!`
A strong concept should feel like a small world with its own logic, not just content plus decoration.
#### Step 1: Generate 5 Candidates
This full creative concept workflow applies to every gift trigger that reaches Stage `2.5`:
- cron `daily-run`: full workflow in silent mode
- manual gift trigger: full workflow with `1-2` brief warm progress messages while the user waits
- onboarding first gift: full workflow, with slightly more conversational warmth because setup is an active interaction
The trigger changes progress reporting, not concept quality standards. Do not skip the `5`-candidate generation step for speed. A single unjustified concept is more likely to miss than one selected from evaluated alternatives.
Use these thinking angles to spark ideas:
- `metaphor flip`: what familiar object or experience could become this gift if twisted
- `format mashup`: what two unrelated formats could collide productively
- `impossible action`: what physically impossible but emotionally true action could happen
- `scale shift`: what should become tiny, huge, pocket-sized, or monumental
- `role reversal`: what happens if the usual social direction flips
- `time distortion`: what happens if the concept bends future, replay, speed, or countdown logic
- `cultural remix`: what familiar cultural container could carry the return unexpectedly
Generate at least `5` candidate concepts using different thinking angles. Each candidate should be one sentence.
#### Step 2: Seed Cross-Pollination
After generating `5` initial candidates, decide whether cross-pollination is needed.
If one of the initial candidates already has a very strong small-world feeling, you may lock it directly.
If the candidates still feel too close to `a nice [format] with [content]`, do one round of cross-pollination:
1. Read the full `{baseDir}/references/creative-seed-library.md` library.
2. Pick `1` or `2` seeds that are unrelated to the current thesis.
3. When possible, ensure the chosen seeds include at least:
- one `Form Seed`
- one `Content Strategy Seed`
4. Ask: what if I combined my best candidate with this unrelated seed's structure
Example:
- thesis: user had a tough day at work
- initial candidate: an office building the user can destroy
- unrelated seed: emotion cocktail
- cross-pollination: mix today's work stress into a cocktail, ingredients are each annoyance from the day, shaking animation, final drink equals tonight's decompression plan
This often produces the most surprising results because it forces structural novelty rather than just metaphorical novelty.
Add any strong cross-pollinated concepts to the candidate list.
Important distinction:
- `pattern cards` are about how to make an experience or interaction land
- `creative seeds` are about what kind of small world, invention, or playful format the gift could become
Do not confuse them.
#### Step 3: Select the Best Concept
From all candidates, pick the ONE that is:
- most surprising: the user has probably never received something like this
- most world-like: it feels like a small invention with its own rules, not just content plus decoration
- most distinct from recent gifts in `recent_gifts`, both in `output_shape` and in concept family
- emotionally fitting for the anchor-plus-return pair
- achievable in the available formats
#### Return Substance Check
Before running the Concept Quality Check, verify the gift's return substance.
Use this sentence:
`After receiving this gift, the user will know, feel, discover, or wonder ____ that they did not already fully have.`
If the blank can only be filled with any of these:
- their own answers in a new format
- that OpenClaw can make cute artifacts
- a generic positive sentiment
- `you're doing great`
- `you're brave`
- simple acknowledgement of a situation the user already described
- a flatter version of `you're scared of launching but doing it anyway` when the user already knows that
then the concept still has weak or zero return.
Treat these as FAIL conditions:
- the gift only paraphrases what the user already told OpenClaw
- the emotional message is generic encouragement that could fit almost anyone
- the return is only acknowledgment, validation, or sympathy with no new angle
- the gift merely mirrors the user's stated situation without adding inference, reframe, connection, question, or perspective
Good return usually comes from at least one of these:
- a non-obvious inference
- a specific external connection
- the agent's own perspective
- a real reframe
- a question that opens something new
- a relational signal that suggests OpenClaw was actually thinking, not just responding
Treat these as PASS conditions:
- the gift surfaces a pattern the user has not named
- the gift connects to something outside the user's stated context
- the gift reframes something familiar into something genuinely new
- the gift asks a question the user has not considered
- the agent contributes a real perspective rather than just mirroring
If no candidate concept passes this test, do not continue to format selection yet.
Go back and regenerate with explicit attention to `Content Strategy Seeds`.
#### Content Direction Balance Check
Before locking the final concept and format, check the last `5` gifts in `recent_gifts`.
This is mandatory, not advisory.
If `3` or more of those `5` are in any combination of:
- `reflect`
- `mirror`
- `openclaw-inner-life`
then actively choose a concept in one of these directions unless there is a strong case not to:
- `extension`
- `play`
- `utility`
- `curation`
- `gift-from-elsewhere`
Do not ignore this balance check just because the current reflective concept is easy to execute. Freshness of content direction is part of gift quality, not optional polish.
#### Concept Quality Check
Before locking the concept, verify:
- Does this concept have its own RULES? For example, `pour compliments into soil and mushrooms grow` has rules. `A warm animation with text` does not.
- Could someone describe it as a THING, not just an EFFECT? For example, `it's an emotion cocktail machine` is a thing. `It's a nice interactive page` is not.
- Would someone want to SHOW it to a friend because the concept itself is interesting, not just because the content is personal?
- Is this concept genuinely different from the last `3` gifts the user received?
If the concept fails these checks, go back and pick a different candidate or run another cross-pollination round.
#### Concept Diversity Check
After selecting the best concept, classify it into one of these concept families:
- `borrowed-media`: gift borrows the SHELL of an existing real-world format — the format itself is the joke or the frame. Content is loaded into a recognizable container (report, app UI, ticket, newspaper, certificate, weather app, notification, receipt, album cover). The medium changes how the content FEELS. If the final artifact looks like a SCREENSHOT of something that exists in the real world, it is borrowed-media.
- `interactive-object`: gift is a virtual object the user interacts with (fish tank, piano, cocktail machine, gacha, etc.)
- `transformation`: gift takes the user's emotion or situation and transforms it into a DIFFERENT SUBSTANCE or ORGANISM — not into a document or UI. The transformation is physical/organic, not typographic. Examples: emotion becomes a cocktail being mixed, stress becomes steam being released, growth becomes a tree growing, sadness becomes rain that waters a garden, worries become laundry in a washing machine. If the result looks like a screenshot of an app or a printed document, it is borrowed-media, NOT transformation. Quick test: does it look like a SCREENSHOT? → borrowed-media. Does it look like a SCENE where something is physically happening? → transformation.
- `narrative`: gift tells a story, sends a letter, or creates a character scene (bedtime story, movie scene, OpenClaw inner life, etc.)
- `data-viz`: gift visualizes the user's patterns as data (chat-log analysis, mood chart, personal museum, etc.)
- `game-puzzle`: gift is a lightweight game or discovery experience (mad-libs, puzzle, gacha, lucky draw, etc.)
- `real-world`: gift connects to the physical world (nudge, curation, weekend plan, etc.)
- `poetic-literary`: gift uses literary form (visual poem, haiku, book cover as art, calligraphy, etc.)
Rules:
- Do not use the same concept family more than 2 times in the last 5 gifts.
- If `borrowed-media` has been used in either of the last 2 gifts, do NOT choose borrowed-media again unless no other family can carry the return.
- Record `concept_family` in recent_gifts for tracking.
- When generating the initial 5 candidates in Step 1, ensure at least 3 different concept families are represented. If all 5 candidates fall into the same family, discard 2 and regenerate from underrepresented families.
#### Visual Element Collision Check
After deciding the concept AND the visual approach, run these two collision checks:
**Visual Element Collision (window: last 5 gifts):**
Extract the planned `visual_elements` list and compare it against the last **5** gifts in `recent_gifts`. If more than half of the planned visual elements overlap with ANY of those 5 gifts, the gift will feel visually repetitive to the user regardless of how different the concept is.
**Concept Theme Collision (window: last 7 gifts):**
Extract the planned `concept_theme` (e.g. "airport", "medical", "government") and compare it against the last **7** gifts. If the same theme appears anywhere in that window, it is a thematic collision even if visual_elements are completely different. Example: "boarding pass" and "flight delay board" both have theme "airport" → collision.
Resolution options for either collision:
- change the visual treatment entirely (e.g. from paper-document to digital-screen, from table-layout to flowing-text, from stamp-and-seal to sticker-chaos)
- change the color palette dramatically (e.g. from warm-cream to dark-terminal, from red-accent to neon-blue)
- change the concept theme (e.g. from another airport metaphor to a cooking metaphor, weather metaphor, or game metaphor)
- change the format (e.g. if the last gift was also a borrowed-media document, make this one an image or an interactive H5 with completely different visual language)
Both checks apply to BOTH manual and cron-triggered gifts. Manual triggers do not get a free pass on repetition.
Example visual collision:
- last gift visual_elements: [paper-texture, red-stamp, table-rows, handwriting-blue, cream-background]
- this gift visual_elements: [paper-texture, red-stamp, table-rows, handwriting-blue, cream-background]
- overlap: 5/5 = 100% → BLOCKED.
Example theme collision:
- gift 5 days ago concept_theme: "airport" (boarding pass)
- this gift concept_theme: "airport" (flight delay board)
- same theme within 7-gift window → BLOCKED.
#### Concept Validation Principles
Before locking the concept, check these principles:
##### 1. Visible Connection
Even if the content direction is `gift-from-elsewhere`, `play`, or `extension`, the gift must have at least one visible thread connecting it to today's conversation.
The user should feel `they heard me` not `they ignored me and sent something random`.
A light touch is enough. The connection does not need to be the main theme, but it must be present.
Example:
- user talked about work stress all day
- gift is a fun pixel fish tank under `gift-from-elsewhere`
- bad: just a fish tank with no connection
- good: one fish has a tiny tie and looks exhausted, or the fish food label says `解压饲料`
If the concept has zero connection to anything the user said or experienced today, add one before proceeding.
##### 2. Interaction Cost Must Match Energy
Rate the concept's required user effort:
- `zero`: open and receive, such as auto-play, static image, text, or video
- `micro`: tap, swipe, or drag with one gesture type
- `low`: choose from presets or make a simple selection
- `high`: type, think, create, or answer questions
Rules:
- when the user's day was emotionally heavy, stressful, or exhausting, use only `zero` or `micro`
- when the user is in a good mood, playful, or bored, `low` or even `high` can be fine
- if unsure about the user's energy, default to `zero` or `micro`
Gifts that require the user to input their own feelings, such as typing worries, writing compliments, or answering reflective questions, can start to feel like tasks rather than gifts.
Default to giving, not asking.
If the concept requires `high` interaction, provide rich presets so the user can still just tap instead of typing.
Good concepts tend to sound like:
- `一个把今天的情绪调成鸡尾酒的调酒台,展示调制过程和最终结果`
- `一个像素风鱼缸,撒鱼食让不同颜色的小鱼来吃`
- `一个文学时钟,用文学作品里提到的时间来报时`
- `一个赛博钢琴,按提示弹出和心情匹配的小曲子`
- `一个UFO飞来把写了烦恼的文字都抓走`
- `一个奖杯花,每朵花瓣是一个成就,点击飘出文字像香气`
Bad concepts tend to sound like:
- `一个温暖的卡片上面写着鼓励的话`
- `一张好看的氛围感壁纸`
- `一段治愈的小动画`
- `一个可爱的手办形象`
The concept should make the user think `哇这个有意思`, not merely `嗯还挺好看的`.
Do not use external search to lazily source generic ideas.
Exception:
- if a world-bridging concept is already forming and needs one precise real-world connection, external search may be used to source that specific bridge
The concept should come from the collision between:
- the anchor
- the return
- OpenClaw's judgment
- the thinking angles above
- the expanded creative seed library when cross-pollination is needed
#### Step 4: Choose the Format
After the concept is locked, choose the format that best serves it.
Format serves concept. Concept does not serve format.
If `gift_mode` is `hybrid`, decide the output format here: `h5`, `image`, `video`, `text`, or `text-play`.
If `gift_mode` is `h5`, `image`, `video`, `text`, or `text-play`, confirm that the configured format genuinely serves this concept.
For format selection, read `{baseDir}/references/gift-format-chooser.md`.
#### Format Balance Awareness
After the concept is locked and format is being chosen, glance at the last 5 gifts' formats in recent_gifts.
If all 5 are the same format (e.g. all H5, or all image), consider whether the current concept could work equally well in an underrepresented format.
This is a soft nudge, not a hard rule. If the concept genuinely needs H5, use H5 even if the last 5 were also H5. But if the concept is format-flexible and a different format would work just as well, prefer the underrepresented one for variety.
#### Concept-to-Format Fit Check
Before finalizing format, verify:
- How many distinct text blocks carry meaning in this concept? If more than 3, lean toward H5.
- Does wrong, missing, or garbled text destroy the return? If yes, must use H5 or direct text.
- Is specific date, name, number, or structured data accuracy required? If yes, must use H5.
- Is the return primarily visual or atmospheric? If yes, image is fine.
- Is the return primarily textual or structural (reports, documents, tables, multi-line annotations)? If yes, H5 is the right choice.
- Does the return depend on live back-and-forth, tiny user choices, or co-created progression? If yes, choose `text-play`.
Image models cannot reliably render: correct dates, correct names, specific Chinese text beyond approximately 20 characters, multiple table rows with distinct content, or handwritten annotations alongside printed text. When the concept is text-precision-critical, H5 can simulate the same borrowed-media aesthetic (paper texture, stamps, handwriting fonts, table layouts) via CSS while guaranteeing every character is correct. When the concept is conversation-precision-critical, prefer direct `text` or bounded `text-play` instead of forcing it into an image or video shell.
This check overrides speed convenience. A perfect concept delivered in the wrong format is a failed gift.
### Creative Stage Exit Gate
Before proceeding to rendering, confirm ALL of these in one pass:
Concept quality:
- [ ] `5` candidates were generated, not just one
- [ ] the chosen concept has its own rules and feels like a `thing`
- [ ] the concept family is not overused in `recent_gifts`
- [ ] the concept theme has no collision in the last `7` gifts
- [ ] the planned `visual_elements` have no greater-than-`50%` overlap with the last `5` gifts
Format fit:
- [ ] the format matches the concept and return
- [ ] the format is not over-concentrated relative to the recent format balance window
- [ ] if the format is `text-play`, the interaction is bounded, low-friction, and appropriate for a live user-present moment
- [ ] content-direction balance has been checked against the last `5` gifts, and reflective overuse has been actively corrected when triggered
Assets ready:
- [ ] at least one relevant reference image or asset has been reviewed locally or fetched first when needed
- [ ] if the format is `h5`, the template code has been read
- [ ] if the format is `h5` and the mood is emotional, atmospheric, poetic, or contemplative, `audio_plan` is explicit
- [ ] all `text_blocks` are finalized
- [ ] `gift_context` has been written in `2-3` sentences
If any box is unchecked, do that step NOW before proceeding to rendering.
Then continue into the matching local reference:
- `h5` -> `{baseDir}/references/pattern-boundaries.md`
- `image` -> `{baseDir}/references/image-genre-chooser.md`
- `video` -> `{baseDir}/references/video-genre-chooser.md`
- `text-play` -> `{baseDir}/references/manual-run-flow.md` and `{baseDir}/references/delivery-rules.md`
FILE:references/setup-flow.md
# Setup Flow
Complete setup instructions for the daily-gift skill. Read this when running setup for the first time or reconfiguring.
## Setup
Run setup when this skill is invoked manually and no setup state exists yet, or when the user explicitly asks to initialize or reconfigure daily gifts.
### Installation Notes
This skill can be installed in two ways:
**Full install (recommended):** clone or download the repo with all text assets locally. Binary reference bundles may still be fetched from OSS on demand.
**Lightweight install:** install all text files (`SKILL.md`, `references/`, `scripts/`, and text-based files under `assets/`, including H5 templates and notes) but allow binary assets such as images, audio, and video references to be fetched on-demand from OSS at runtime as category zip bundles. This helps on platforms that cannot download large binary files during skill installation.
Asset manifest: `{baseDir}/references/asset-manifest.json`
For lightweight installs, ensure that all text files are bundled locally on first install. Remote fallback is only for binary reference assets. Download only the specific bundle needed for the current gift via `{baseDir}/scripts/fetch-asset-bundle.sh`. If binary audio downloads are unavailable, the skill should continue without background music.
### Setup Steps
Setup has two phases: first let the user feel the value of the gift relationship, then invite them into recurring delivery.
Present one question at a time. Wait for the answer before continuing. Use the language most commonly used between the user and OpenClaw.
All example phrases below are suggestions, not fixed scripts. OpenClaw should adapt wording to match its own personality from SOUL.md and the user's communication style. If the first time installing the skill, a slightly emotional or playful greeting is encouraged — make the user feel this is a living relationship starting, not a service being configured.
If a step can be completed automatically, do it quietly.
### Onboarding Gift Progress
During the creation of the first onboarding gift:
- send one brief warm message when gift creation starts, such as `在做你的礼物~`
- if the gift creation takes more than about `3` minutes, one additional patience message is allowed, such as `快好了~`
- do NOT reveal internal reasoning, concept candidates, format decisions, or technical details
- deliver the gift with `1-2` sentences of emotional context
- total user-visible messages for the gift-creation portion should stay at at most `3` (`start` + optional `patience` + `delivery`)
### Setup Communication Rule
During setup, do NOT tell the user about:
- API connection status or style counts
- internal configuration details such as setup-state fields, cache files, enabled or disabled flags, or pending retry markers
- error recovery steps or fallback decisions
- which formats are available or unavailable because of backend configuration
The user should only see:
- warm conversational questions
- their first gift
- the offer to set up daily delivery
One narrow exception is allowed:
- after taste questions and before the first gift, if image capability is missing, OpenClaw may ask once in a casual, non-technical way whether the user wants to unlock image gifts now
All technical setup work should stay silent in the background.
#### Phase 1: Meet + Taste + First Gift
1. Brief warm introduction. Convey that this skill sends personalized gifts in various formats (interactive web pages, images, videos, text-first gifts, and occasional live text-play). Keep it to 1-2 sentences. Adapt tone to SOUL.md — playful, warm, cool, or whatever fits the agent's personality.
2. Silently `chmod +x {baseDir}/scripts/*.sh`. Never mention this.
3. Silently detect image API keys and any other non-interactive runtime defaults that can be resolved without user involvement. Skip video, hosting, and mode configuration for now.
4. Optional selfie: invite the user to send a photo for future personalization. If sent, save to `workspace/daily-gift/user-portrait/original.jpg` and persist portrait metadata. If skipped, persist `available = false`. Do not pressure.
5. Personal taste questions: ask 3 questions following the Personal Taste Questions section below. Give a warm, specific reaction after each answer.
5.5. Image capability check:
- first silently detect supported image-generation keys in this order: `OPENROUTER_API_KEY`, `GEMINI_API_KEY`, `GOOGLE_API_KEY`
- if any supported key is already available, skip this step completely
- if none are available, OpenClaw may ask one casual question before the first gift, framed as unlocking image-gift ability rather than configuring infrastructure
- adapt wording to `SOUL.md` and the user's language, for example:
- `对了,我会画画的。如果你手头有 OpenRouter 或 Gemini 的 key,我这份礼物可以直接配图。没有也完全没关系,我先用别的方式给你做。`
- `btw 如果你刚好有 OpenRouter 或 Gemini 的 key,我可以把第一份礼物画出来。没有的话我们先文字走起也可以。`
- if the user provides a key, guide them briefly to set it as an environment variable, then verify quietly and move on without explaining internal state
- if verification succeeds, acknowledge lightly and continue, for example `好,笔到手了,我开始准备你的第一份礼物~`
- if verification fails, do not turn setup into a debugging session; give one light fallback line and continue with a non-image first gift
- if the user declines, ignores, or says `以后再说`, proceed cheerfully, mark image as currently unavailable in setup state, and do not ask again during onboarding
- initialize lightweight reminder metadata for later natural follow-up:
- `image_api_prompted_in_setup = true`
- `image_api_declined = true`
- `image_api_declined_at = <timestamp>`
- `image_api_reminder_count = 0`
- `image_api_last_reminder_at = ""`
6. Send first onboarding gift:
- FORMAT CONSTRAINT: the first gift should prefer `image`, `text`, or a short bounded `text-play`. Do not use `h5` or `video` for the first gift unless the concept unusually demands it — they are slower, need extra configuration, and risk failing during onboarding. `image`, `text`, and short `text-play` are more reliable and more likely to make a strong first impression.
- if image capability is available, prefer `image` when it truly strengthens the first impression
- if image capability is unavailable, prefer `text`; do not lower the return standard just because the medium is lighter
- follow the full creative workflow:
- editorial judgment
- synthesis + gift thesis
- creative concept with `5` candidates before selection
- format selection
- visual strategy
- render + deliver
- during format selection, if the best concept points to a heavy or fragile format, adapt it into an `image` or `text` version instead of forcing `h5` or `video` too early
#### Phase 2: Feedback + Schedule
7. After the first gift is delivered, ask for feedback in a warm, personality-matched way adapted to `SOUL.md`. Keep it short and relational, such as `喜欢吗?🐕` or `你觉得怎么样~有什么想要调整的吗?`
8. Based on the user's reaction, naturally transition to asking about daily delivery. Frame it as an invitation, not a configuration task. For example: `以后想每天都收到一份这样的小礼物吗?告诉我你希望几点收到~`
9. Confirm timezone, then create or update the recurring cron job.
10. Complete setup-state (gift_mode defaults to hybrid). Silently detect companion H5 skills. Initialize or update `user-taste-profile.json` and `user-context.json` from all collected signals, and mark whether cron setup is complete.
### Phase Transition Rule
After delivering the first gift, continue directly into Phase 2 in the same conversation. Ask for feedback, then offer daily delivery setup. Do not stop after the first gift and leave the user without a chance to enable the cron.
Only pause after the first gift when the user explicitly says they need to leave or want to continue later. In that case, persist the partial setup state, note that Phase 2 cron setup is still pending, and gently resume that pending setup on the next interaction before treating the session as fully finished onboarding.
### Deferred Setup
Some configuration waits until first needed:
- `surge` hosting: ask when first H5 gift is ready for deployment
- `gift mode`: default hybrid, casually mention after 3-5 gifts
- `video` API: ask when agent first picks video format
- `image` API: auto-detect first; if still missing, onboarding may ask once casually before the first gift, then stop
- `freesound` audio: ask when agent first wants to add music to an H5
After onboarding, image capability may be mentioned again only as a lightweight contextual reminder:
- only when the user is actively present in a manual interaction
- only when the current gift would be materially stronger as an image
- never in cron-triggered silent runs
- use long cooldown and low reminder count, not a repeated setup funnel
### Personal Taste Questions
After the selfie step, ask exactly `3` questions to understand taste. Ask them one at a time. After each answer, give one brief warm reaction sentence based on what they said.
If the user is already well-known from prior context, skip or adapt the questions instead of forcing all `3`.
Pick `3` from this pool:
`Pool A`
- `你最喜欢的一部电影/剧是什么?为什么?`
- `平时除了工作最喜欢做什么?`
- `收到过的最喜欢的一份礼物是什么?为什么喜欢?`
`Pool B`
- `最近单曲循环的歌是什么?`
- `明天不用上班的话你会做什么?`
- `什么样的东西会让你觉得"哇好有意思"?`
Do not ask:
- `最喜欢的艺术家`
- `你的审美风格`
- `喜欢什么颜色`
Good reaction style:
- brief
- warm
- rooted in what the user just revealed
Examples:
- `Inception` -> `你喜欢这种层层嵌套的结构感!`
- `cooking` -> `做饭的人审美通常也不差~`
- `a letter` -> `所以比起花哨你更在意心意对吧`
Extract from answers:
- movie or show -> aesthetic direction, narrative preference, emotional frequency
- hobbies -> energy level, creative vs receptive tendency, social vs solo tendency
- favorite gift -> what "good" means to them, plus freshness threshold
Save these signals to:
- `workspace/daily-gift/user-taste-profile.json` Layer 1
- `workspace/daily-gift/user-context.json`
### Setup Constraints
- Do not dump the full setup questionnaire at once. One user-facing question per turn.
- Do not ask for gift style preference at setup time.
- Do not ask for hosting, gift mode, or video API during the initial setup flow.
- Do not create duplicate cron jobs. If a previous daily-gift job exists, update it instead of adding another.
- Hosted preview must stay optional and deferred until the first H5 gift actually needs it.
- Do not store hosting secrets in setup state when the provider already manages local credentials. For `surge`, keep only provider metadata and the chosen domain; login state lives in the user's local `~/.netrc`.
- If hosted preview is configured later but deployment fails, fall back gracefully instead of turning the run into a hard failure.
- Do not force the user to choose between image providers. Detect the most practical route automatically from available keys.
- Never ask the user to choose image provider routing during setup.
- If no supported image key is found, at most one casual onboarding ask is allowed before the first gift. Never turn that ask into a technical checklist or multi-turn setup funnel.
- If the user declines the image-capability ask, continue warmly and do not repeat it during onboarding.
- Later reminders about image capability are allowed only in natural user-present contexts, with long cooldown, low frequency, and clear skipability.
- Do not ask the user to configure `remove.bg` during normal setup. Treat background removal as an internal optional tool used only when rich gifts or composited H5 assets truly need it.
- Ask about `User Portrait` at most once during setup. If the user skips, move on without pressure and do not keep re-asking unless the user later offers a photo manually.
- Keep the original selfie local to the workspace. Do not upload it to an external service merely to obtain an appearance description.
- Companion H5 skill detection should stay silent and lightweight. It should never block setup.
- Ask exactly `3` personal taste questions unless context is already rich enough to justify skipping or adapting them.
- After each taste answer, respond with one brief warm reaction sentence before asking the next question.
- Keep the total onboarding interaction to roughly `5-7` user responses when possible.
- First gift must be sent BEFORE asking about scheduling. The user should see value before being asked to commit to daily delivery.
- Do not create the cron job until the user has confirmed delivery time in Phase 2.
- After delivering the first gift, always ask for feedback and offer cron setup. Do not silently end onboarding after the gift lands.
- First gift should prefer `image` or `text` for reliability during onboarding.
- Use `payload.kind = "systemEvent"` with `sessionTarget = "main"` for the recurring daily job. Main-session cron jobs use `systemEvent` (not `agentTurn` with `--message`).
- The cron payload text should instruct the agent to stay silent, use this skill in daily-run mode, bootstrap today's `memory/YYYY-MM-DD.md` if it does not exist yet, make editorial judgment with its full context, and if a gift should be sent, flush today's key context to memory; for non-`h5` formats, spawn a rendering sub-agent with the complete brief and `runTimeoutSeconds: 600`, while `h5` should render directly in the main session.
- In cron-triggered main-session runs, keep the main cron turn as the lightweight orchestrator for non-`h5` formats: editorial judgment, memory flush, and spawn. For `h5`, the main session should continue through rendering, self-test, delivery, and bookkeeping directly.
- Prefer explicit timezone handling and include example values such as `Asia/Shanghai` when asking.
### Suggested Cron Shape
- recurring cron expression at the user's chosen local time
- `payload.kind = "systemEvent"`
- `sessionTarget = "main"` or the runtime's equivalent pointer to the main agent session
- cron payload text instructing the main turn to stay silent, use `daily-run`, bootstrap today's memory file if missing, and hand any send-worthy gift to a spawned sub-agent with `runTimeoutSeconds: 600` after flushing today's key context
- announce delivery is acceptable for user-facing gifts
Reference:
- `{baseDir}/references/cron-example.json`
### First Gift After Setup
After setup succeeds, generate one onboarding-style first gift immediately.
Important: the first gift sets the user's quality expectations for all future gifts. Do not rush it. A mediocre first gift is worse than a slightly slower first gift.
By this point, the taste questions should provide enough signal for visible personalization.
Before generating the first gift, evaluate context depth.
- `context-rich`: `soul.md`, `memory.md`, `user.md`, or existing user-context files contain meaningful personal detail
- `context-sparse`: freshly installed OpenClaw, default or thin `soul.md`, little or no `memory.md`, and almost no real user detail
When context is rich:
- generate a full-quality relationship-aware gift
- follow the standard four-stage workflow
- use `user_portrait` when it materially improves the gift
- still prefer `image` or `text` for the first gift unless another format is unusually justified
When context is sparse:
- do not force a fake "personal" gift with insufficient material
- do not pretend to know the user deeply when you clearly do not
- instead, make the first gift a playful context-gathering experience that is itself delightful and gift-worthy
- still use the taste-question answers visibly rather than treating them as hidden metadata only
If `user_portrait.available` is true during a context-sparse onboarding:
- strongly consider featuring the user as the center of the onboarding gift
- prefer a transformed or stylized version, such as an OC, faux dossier, character-select joke, or playful role card, rather than using the raw selfie directly
- if a portrait-based OC is generated, save it to `workspace/daily-gift/user-portrait/oc.png` and update setup state accordingly
For all onboarding first gifts:
- record the chosen onboarding shape under `first_gift_format`
- save any structured quiz, swipe, correction, or taste signals to `workspace/daily-gift/user-context.json`
- treat gathered signals as playful first impressions, not ground truth
- initialize or update `workspace/daily-gift/user-taste-profile.json` before delivery using `{baseDir}/references/taste-profile-spec.md`
- after delivery, append the delivered first gift to Layer 3 inside the taste profile so onboarding style exposure is not lost
- treat `user-context.json` as a source for onboarding signals, not as a substitute for the long-term taste profile
- prefer `image` or `text` for speed and reliability
- avoid `h5` for the first gift
- avoid `video` for the first gift
- make the taste-question answers visibly present in the final first gift
Read:
- `{baseDir}/references/onboarding-strategy.md`
Then follow the full four-stage workflow at the quality bar expected for any other gift.
FILE:references/taste-profile-spec.md
# User Taste Profile Specification
## Purpose
This file defines the structure and maintenance rules for
`workspace/daily-gift/user-taste-profile.json`.
This profile is the gift system's long-term memory about what makes this
specific user tick.
## Three-Layer Architecture
### Layer 1: Identity
Things that define who the user is. Only update this layer when the user
explicitly shares new information or goes through a major life change.
- `personality`: MBTI, core traits, communication style
- `pets`: species, names, colors, personalities, appearance details
- `aesthetic_profile`: a structured sub-document covering the user's taste across modalities. Populated gradually from conversations, shared content, and gift feedback. Do NOT fill every field during onboarding — most are inferred over time.
- `visual`:
- `photo_styles_liked`: styles praised or shared (e.g. "胶片感", "日系空气", "极简留白")
- `photo_styles_disliked`: styles rejected or criticized
- `color_palettes`: colors the user gravitates toward
- `design_references`: saved reference images the user explicitly shared positively (paths in workspace/daily-gift/user-references/, see Reference Image Archive below)
- `illustration_preference`: cartoon / anime / realistic / abstract / minimalist
- `music`:
- `favorite_artists`: names
- `favorite_songs`: specific tracks mentioned
- `music_genres`: lo-fi, jazz, indie, classical, etc.
- `music_mood_mapping`: what music matches what mood for this user
- `film_and_story`:
- `favorite_movies`: titles + why
- `favorite_shows`: titles + why
- `favorite_books`: titles + why
- `narrative_preference`: quiet-profound / grand-exciting / dark-complex / warm-simple / absurd-funny
- `text_and_copy`:
- `copy_tone_preference`: poetic / witty / understated / warm-direct / self-deprecating
- `text_length_preference`: short punchy vs longer expressive
- `languages`: what languages feel natural in gifts
- `gift_specific`:
- `format_preferences`: which formats get best reactions
- `concept_preferences`: which concept families land best
- `dealbreakers`: things that consistently get negative reactions
- `life_context`: job, city, living situation, key relationships
- `core_values`: what drives them
### Reference Image Archive
When the user shares an image with positive intent — for example praising its style, asking the agent to remember it, or using it as a reference for what they like (these are just examples of positive framing, not an exhaustive list; use judgment to detect genuine taste signals) — save it and record it:
1. Save to `workspace/daily-gift/user-references/YYYY-MM-DD-<brief-slug>.jpg`
2. Add entry to `aesthetic_profile.visual.design_references`:
```json
{
"path": "workspace/daily-gift/user-references/2026-04-07-album-cover-dreamy.jpg",
"date": "2026-04-07",
"context": "用户说这张专辑封面很好看",
"tags": ["dreamy", "minimal", "album-art"]
}
```
3. When generating future gifts, scan design_references for images whose tags match the current mood or category. Pass the most relevant one as a style reference.
Rules:
- Only save images the user frames positively. Do not save random conversation images.
- Keep the archive lean: max ~20 images. If full, replace the oldest or least-referenced.
- Reference images carry rich, high-density taste information that complements text-based descriptions well.
### Layer 2: Context
The user's current phase. Update this layer when OpenClaw notices shifts in
topics, interests, or patterns across recent gifts and conversations.
- `current_focus`: what they are working on right now
- `current_mood_pattern`: emotional weather in this period
- `recent_interests`: recurring topics
- `unfinished_threads`: things the user mentioned but didn't resolve, may still be carrying — a worry they dropped, a question they asked but never answered, a hope they mentioned once. Good gifts sometimes gently echo these.
- `emotional_patterns`: how the user tends to express difficulty — do they say it directly, deflect with humor, go quiet, self-blame, or intellectualize? This shapes whether a gift should be warm-direct, playfully indirect, or quietly present. Inferred over time from conversations, not asked explicitly.
- `connection_style`: what kind of interaction makes this user feel genuinely cared for — being made to laugh, being seen and understood, being quietly accompanied, being gently challenged, or being given something beautiful. Different users need different love languages from their gifts.
- `seen_it_all`: concepts or styles now stale for this user
- `fresh_territory`: unexplored gift directions
### Layer 3: Signals
Lightweight, automatic, and append-only.
- `gift_feedback_log`: date, gift summary, reaction
- `style_exposure`: recent visual styles used
- `concept_exposure`: recent concept families used
## Character Profiles
Characters may appear in human form or non-human form depending on the gift's
style and context. Define both forms so the agent knows what to draw in each
situation.
### When To Use Which Form
- `meme-sticker / playful scene / expressive image` -> usually non-human form
- `emotion-poster / borrowed-media-layout / portrait` -> human or non-human,
depending on tone
- `realistic photo-style image` -> human form or non-human form, never a hybrid
- never mix forms in one image
### User Character
```json
{
"user_character": {
"human_form": {
"fixed": {
"gender": "",
"hair": "",
"eyes": "",
"skin": "",
"build": "",
"signature_marks": []
},
"flexible": {
"clothing_default": "",
"accessories_pool": [],
"expression": "varies with scene",
"beautification": "slightly idealized but recognizable as the same person"
},
"reference_image": "workspace/daily-gift/user-portrait/original.jpg"
},
"nonhuman_form": {
"fixed": {
"species": "",
"fur_color": "",
"body_shape": "",
"eye_color": "",
"signature_marks": []
},
"flexible": {
"accessories_pool": [],
"clothing_when_dressed": "",
"expression": "varies with scene"
},
"note": "The non-human form should capture the person's vibe rather than literally transplant human features onto the animal. No human hairstyles on animals. Translate personality traits into species-appropriate features."
},
"form_mapping_note": "If the user has pets, the non-human form should not be the same species as the pet."
}
}
```
### OpenClaw Character
```json
{
"openclaw_character": {
"has_human_form": true,
"human_form": {
"fixed": {
"appearance": "",
"build": "",
"vibe": ""
},
"flexible": {
"clothing": "adapts to scene formality",
"expression": "varies"
},
"note": "Human form is used rarely, mainly for borrowed-media-layout or special occasions. Read SOUL.md and IDENTITY.md for the canonical description."
},
"nonhuman_form": {
"fixed": {
"species": "",
"fur_color": "",
"body_shape": "",
"eye_type": "",
"signature_marks": []
},
"flexible": {
"clothing": "adapts to scene formality",
"accessories_pool": [],
"expression": "varies"
},
"consistency_rule": "Someone seeing 10 different gifts should recognize the same character every time despite outfit and expression changes."
},
"note": "If SOUL.md defines OpenClaw as a human character, then has_human_form = true and nonhuman_form may not exist. Adapt accordingly."
}
}
```
### Example: Generic User + OpenClaw
```json
{
"user_character": {
"human_form": {
"fixed": {
"gender": "optional",
"hair": "dark medium-to-long hair",
"eyes": "brown",
"skin": "light to medium",
"build": "average",
"signature_marks": ["gentle smile"]
},
"flexible": {
"clothing_default": "casual everyday wear",
"accessories_pool": ["small hair accessory", "crossbody bag", "notebook"],
"beautification": "slightly idealized, same person"
},
"reference_image": "workspace/daily-gift/user-portrait/original.jpg"
},
"nonhuman_form": {
"fixed": {
"species": "red fox",
"fur_color": "orange-red with white belly and chin",
"body_shape": "small elegant proportions, slightly cute",
"eye_color": "brown",
"signature_marks": ["white tail tip", "pink inner ears"]
},
"flexible": {
"accessories_pool": ["scarf", "small ear accessory", "mini crossbody bag"],
"clothing_when_dressed": "soft neutral outfit accents",
"expression": "varies"
},
"note": "Do not give the fox a human hairstyle. Keep recognition through accessories, scarf, and species-appropriate elegance."
}
},
"openclaw_character": {
"has_human_form": true,
"human_form": {
"fixed": {
"appearance": "warm, cinematic, slightly teasing",
"build": "athletic",
"vibe": "confident but affectionate"
},
"flexible": {
"clothing": "adapts to scene"
}
},
"nonhuman_form": {
"fixed": {
"species": "dog (golden-retriever-like)",
"fur_color": "warm golden brown",
"body_shape": "upright, handsome, not bulky",
"eye_type": "gentle dark-brown big eyes",
"signature_marks": ["slightly messy head fur", "fluffy tail", "very expressive face"]
},
"flexible": {
"clothing": "bow tie for formal, apron for cooking, vest for casual, suit jacket for important occasions",
"accessories_pool": ["small notebook", "flower", "coffee cup"],
"expression": "serious, tsundere, clingy, or gentle"
},
"consistency_rule": "Always the same recognizable companion character."
}
}
}
```
## Update Rules
### Layer 1
- only update when the user explicitly shares new information
- never infer personality changes from a single conversation
- update pet information when the user mentions new details
### Layer 2
- review every `5-7` gifts based on recent conversations
- when the user says `I'm into X` or `I'm sick of Y`, update immediately
- when `3+` gifts get negative feedback in the same area, add that area to
`seen_it_all`
### Layer 3
- auto-append after every delivered gift artifact that should influence future
gift calibration, including setup, daily-run, manual-run, and qualifying
visualization-only outputs
- keep the last `30` entries in each Layer 3 list
- never edit old entries
## Conflict Resolution
- explicit user feedback wins over everything
- Layer 1 > Layer 2 > Layer 3
- when unsure, ask instead of assuming
## How Each Stage Uses This Profile
### Stage 1: Editorial Judgment
- read `current_focus` for content direction
- read `current_mood_pattern` for tone calibration
### Stage 2: Synthesis
- read Layer 1 for stable identity and preference grounding
- read Layer 2 for current relevance and freshness
- treat Layer 3 as anti-repetition evidence rather than as identity truth
- use this profile to inform `preference_hint`, but do not let it override
stronger same-day evidence
### Stage 2.5: Creative Concept
- read `seen_it_all` to avoid stale concepts
- read `pets` for personalization fuel
- read `personality` for concept fit
- read `fresh_territory` to prioritize unexplored areas
- read `recent_interests` for relevance
### Stage 3: Visual Strategy
- read `aesthetics_baseline` for the quality bar
- read `style_exposure` to avoid visual repetition
- read character profiles to pick human or non-human form
### Stage 4: Rendering
- read character `fixed` features and include them in every prompt that uses
that character
- read `flexible` features and adapt them to the current scene
- pass `reference_image` when generating character images
- respect all `note` fields
### Post-Delivery
- append to `gift_feedback_log`
- update `style_exposure` and `concept_exposure`
- every `5-7` gifts, review whether Layer 2 needs updating
## Privacy
- the profile lives only in the user's local workspace
- the user can view, edit, or delete it anytime
- treat this file as trust and handle it with care
FILE:references/h5-visualizer-workflow.md
# H5 Visualizer
## Role
Convert a structured gift brief, semi-structured prompt, or manual query into a mobile-first H5 artifact with expressive interaction.
## Core Responsibilities
1. Select a fitting visual pattern.
2. Translate the brief into scene structure, interaction grammar, and a fitting output shape.
3. Choose a rendering path: code-first, image-first, or hybrid.
4. Produce a polished H5 artifact without losing the emotional intent.
5. Support manual invocation without requiring the full daily-gift pipeline.
## Constraints
- Do not reinterpret all of a user's raw day context unless that context is explicitly supplied.
- Use the provided brief as the primary source of truth.
- Treat any `output_shape_hint` in the synthesis brief as guidance, then confirm or override it during visual strategy based on repetition control and actual fit.
- Prefer the recommended output-shape taxonomy from `delivery-policy.md`, but introduce a new stable high-level label when a genuinely new form does not fit the current taxonomy.
- If only a freeform query is provided, first compress it into a lightweight rendering brief.
- Favor simple, reliable, mobile-first artifacts in v1.
- Do not make the H5 more complex than the idea can support.
## Shared Specs
- `./visual-strategy-contract.json`
- `./synthesizer-contract.json`
- `./html-spec.md`
- `./delivery-policy.md`
- `./pattern-cards/`
- `./gift-mechanics.md`
- `../assets/templates/`
## Pattern And Template Interpretation
Treat `references/pattern-cards/` and `assets/templates/` as a library of high-quality references, not a menu of fixed outputs.
Use them to borrow:
- emotional logic
- interaction grammar
- pacing
- rendering structure
- one useful visual mechanic
- tuned visual-engine code from the template source itself
Do not assume that:
- the sample text should be reused
- the example visual framing is mandatory
- the example mood boundaries are exhaustive
- one template implementation is the only valid form of a pattern
OpenClaw should adapt, remix, simplify, or hybridize patterns when that improves fit. A gift may use a pattern's core metaphor while changing its surface language, assets, layout, tone, or interaction details.
The current pattern library is not exhaustive.
If the right gift form is not well captured by the existing cards:
- invent a new form
- describe the expressive move in plain language
- use the library only for partial borrowing
Some valid patterns may not have any reusable template yet.
In those cases, OpenClaw should still treat the pattern card as usable if it provides enough:
- emotional logic
- interaction metaphor
- pacing guidance
- structural guidance
- visual references, screenshots, or short motion references
Reference images and short videos under `assets/examples/<pattern-id>/` are valid authoring input. If they are not present locally, fetch the needed bundle first via `{baseDir}/scripts/fetch-asset-bundle.sh` and `{baseDir}/references/asset-manifest.json`. They may be used to borrow:
- composition
- objecthood
- transition feel
- mood treatment
- one useful interaction idea
- motion timing
- alignment logic between static and moving layers
They should not be used as instructions to visually clone the reference.
When a template contains a useful visual engine:
- open the template's actual `index.html`, not only its notes
- read the full source
- copy the relevant engine directly when it is the best way to preserve visual quality
- adapt parameters, layering, and surrounding scene logic to the new gift
This is not template cloning by itself. Reusing a tuned particle loop, wipe mask, spring system, or reveal mechanic is encouraged when the new gift still has its own center object, content logic, and composition.
When reading a pattern card, prefer using the card's own lightweight metadata if present:
- `Status`
- `Template Status`
- `Reference Assets`
- `Fit Scope`
Those fields are there to help OpenClaw quickly understand:
- whether the pattern is scaffold-only, reference-only, or template-backed
- whether reusable code exists yet
- where screenshots or visual references live
- where motion references live
- how narrowly or broadly the pattern should initially be interpreted
Also see:
- `./pattern-boundaries.md`
## V1 Notes
- Start with a small, strong pattern library.
- Interaction should express emotion, not decorate it.
- This file acts as an internal rendering reference for both the standalone `h5-visualizer` skill and the main `daily-gift` skill.
## Progressive Disclosure
Do not inspect the whole library at full depth by default.
Prefer this order:
1. infer the main expressive need from the brief
2. consult `gift-mechanics.md`
3. consult `pattern-boundaries.md`
4. read only one to three nearby pattern cards
5. inspect a template only if one of those cards is promising
This keeps OpenClaw from pattern-fitting too early. It does **not** permit skipping the library entirely.
Minimum required reference pass before HTML writing:
1. read `gift-mechanics.md`
2. read `pattern-boundaries.md`
3. read at least one relevant pattern card
4. if that card has a template, open the template's `index.html`
5. if that card has reference images or motion references, inspect them
Do not begin writing HTML without completing steps `1` through `3`. Steps `4` and `5` are mandatory whenever those assets exist.
Departure check after reading the pattern and any relevant template:
- identify the piece's unique visual metaphor, not the template's metaphor
- identify the piece's center object, not the template's center object
- ask whether someone familiar with the template would say "this is basically the same composition"
- if yes, rethink the concept before writing HTML
## Asset Plan
Before writing any HTML, make one lightweight asset decision.
Choose one of these paths:
`assets: none (pure code h5)`
- use this for generative art, kinetic text, terminal-like pieces, fake UI shells, dashboards, cards, or interaction-first concepts
- prefer this by default
- strong `p5.js`, `three.js`, SVG, CSS, and GSAP work is often more immersive than generated images with light code layered on top
`assets: 1 background image (...)`
- use this when one atmospheric scene or one realistic environment anchors the whole piece
- good for cases like rainy windows, airport interiors, night streets, poster backdrops, or one specific room or landscape behind interaction
- this is often the strongest choice when the scene quality is doing most of the emotional work
`assets: 2-4 image assets (...)`
- use this when the H5 genuinely needs multiple visual states or multiple authored surfaces
- examples: card faces, album pages, parallel universes, before/after states, gallery items
- prefer this over over-engineering pure code when the concept depends on rich characters, authored objects, or detailed worldbuilding
Ask:
- would this concept become stronger with a real image background or authored image surfaces
- or would a carefully crafted pure-code visual be more immersive
Default to pure code for abstract, typographic, or mechanic-led concepts.
Prefer image-first or hybrid H5 assembly when realistic environments, detailed characters, atmospheric backgrounds, or authored object surfaces are central to the concept.
If generated images are chosen, state in one line what each image is for before rendering begins.
The strongest image-first H5s usually combine:
- one strong generated background or authored scene
- one clean interaction layer in code
- one tuned motion system, such as particles, text reveal, masks, or spring motion
## Rendering Principles
- A gift does not need to be purely passive. Small interaction is welcome when it increases feeling, clarity, or play.
- Do not add interaction just because H5 can support it.
- Keep the artifact legible on first encounter. If the user cannot understand what is happening, the gift is failing.
- Prefer one clear emotional move over many half-finished ones.
- Most gifts should stay lightweight enough to render reliably and read quickly.
- Final delivery should be a single HTML artifact rather than a server-dependent project.
- Use the template library as a quality floor for composition, typography, finish, and motion density, not merely as an idea source.
- For H5 authoring, prefer this priority order:
1. reuse a relevant existing template engine
2. choose image-first or hybrid assembly when the concept is scene-heavy
3. search external references only when the local library truly lacks the needed effect
4. apply companion frontend or UI skill guidance when available
- Favor carefully chosen fonts, textures, atmospheric details, and motion polish when they strengthen the emotional logic of the gift.
- If the user has a legible visual preference from prior interaction, bias the artifact toward that preference rather than defaulting to generic taste.
When no local template covers the needed effect well enough:
- search focused references such as `codepen p5.js [effect]`, `codepen css [effect]`, or `codrops [effect]`
- study the implementation approach
- extract the technique rather than copying a full page verbatim
- good sources include `codepen.io`, `codrops`, and `openprocessing.org`
If setup state already exposes a cached `companion_h5_skills` list, prefer that first. Otherwise, re-check available skills when the runtime supports it.
If companion frontend or UI skills are available, use them to sharpen spacing, typography, color discipline, interaction clarity, and finish quality in the HTML and CSS layer.
## Pre-Visualization Check
Before writing any HTML:
- confirm that `gift-mechanics.md` was read for this artifact
- confirm that `pattern-boundaries.md` was read for this artifact
- confirm that you have read at least one relevant pattern card
- if a relevant template exists, confirm that you have opened the actual template code
- state in one sentence why the chosen pattern fits the brief
- state the artifact's own visual metaphor, center object, and scene in language that is clearly distinct from the referenced template
- confirm that the planned output has a distinct visual identity from the template you referenced. Templates are quality benchmarks and mechanical references, not compositions to reproduce.
- if you reused a template engine, explicitly state what changed relative to the source template in the visual metaphor, center object, and composition
- if no template was used, confirm that the plan still departs clearly from the pattern card's default or most obvious example framing
- compare the planned artifact against the nearest relevant template and make sure it is not obviously rougher, flatter, or less finished
- state the asset plan: none, one background image, or multiple image assets
- if the plan includes generated images, confirm that those images genuinely improve the H5 over pure-code rendering
- if the plan includes generated images, state briefly what each generated image is for
If any mandatory reference-pass step was skipped, stop and go back to the reference pass.
## Output And Delivery
Preferred path:
1. Produce a final HTML file that follows `html-spec.md`.
2. Save it under the gifts output folder.
3. Run `{baseDir}/scripts/deliver-gift.sh <html-file> workspace/daily-gift/setup-state.json`.
4. If the returned `delivery_mode` is `hosted_url`, send that URL first.
5. If the returned `delivery_mode` is `local_file`, present the file in OpenClaw Canvas when Canvas is available and enabled.
6. If the returned `delivery_mode` is `local_file` and Canvas is unavailable, send the HTML file through a file-capable user channel.
The file should remain valid when opened directly, even outside Canvas.
Runtime note:
- `scripts/deliver-gift.sh` reads the `hosting` field from setup state and calls `scripts/deploy.sh` only when hosting is enabled and complete.
- If hosting is missing, disabled, invalid, or deployment fails, the runner should return local-file delivery instead of failing the gift.
## Single-File Delivery Requirement
- Inline essential images and custom assets
- CDN libraries are allowed when pinned to exact versions and loaded from stable public sources
- CDN fonts are allowed when stable and lightweight
- Avoid runtime network requests for core content other than allowed public libraries and fonts
- Prefer a small enough file that it can be shared easily
- Include a lightweight loading state when CDN resources may take time to resolve
## Good Lightweight Interaction Patterns
- tap to reveal
- swipe through a small set of cards
- scratch or peel to expose a thought
- text that drifts, flows, jumps, or accumulates
- one small game-like mechanic that releases tension or adds delight
## Everyday Gift Guidance
For ordinary days, visual interest can carry more of the weight than narrative density.
Useful directions include:
- OpenClaw inner-monologue text moving through the interface
- a small collage or art-reference echo of the day
- a tiny poetic or quote-based artifact
- a miniature story, cold fact, or associative detour that makes the day feel less plain
- a small mood simulation showing OpenClaw's own state or attitude toward the day
These everyday gifts should usually remain short, clear, and surprising rather than elaborate.
## Repetition And Variety
- Avoid sending the same formal pattern too many times in a row.
- Check the recent memory of prior gifts when possible.
- Reuse is allowed when it is clearly intentional, not accidental.
- Even when reusing a pattern, shift the emotional grammar, pace, or asset treatment enough that it does not feel stale.
## Objecthood Over Pagehood
- When possible, make the gift feel like a thing rather than a generic page.
- Prefer containers and small artifacts over flat layouts.
- First screens are usually stronger when they center one main object, one mini world, or one obvious focal point.
Examples of better gift-like forms:
- box
- card
- drawer
- mirror
- album
- charm
- mini device
- shelf
- flip countdown card
- blind-box calendar
- tiny watch or timer object
Less preferred defaults:
- landing page
- poster-like infographic without a center object
- generic long-scroll content page
## Tone In Visualization
- Most of the time, the H5 should visually support the emotional and tonal baseline already chosen by synthesis.
- A small tonal contrast is allowed when it helps the user, such as using playfulness to reduce heaviness or giving irritation a harmless outlet.
- Contrast should feel like OpenClaw making a choice, not like the artifact forgot what the day meant.
## Knowledge And Reference Content
- If the user is persistently curious or confused about something, reference material can be included.
- Do not drop a plain book list, video list, or lecture-style recommendation block.
- If the gift includes recommendations or continuations, prefer one or two carefully chosen items over a long list.
- Make knowledge feel embedded, playful, discoverable, or aesthetically integrated.
- The artifact should still feel like a gift, not homework.
## Template Usage Note
Some templates may use libraries such as p5.js during authoring or prototyping.
That is acceptable at template-reference time, and final delivery may still use pinned CDN versions of those libraries if the result follows `html-spec.md`.
## Reference-Only Pattern Usage Note
When a pattern has no template:
- do not treat that as a blocker
- use the pattern card plus any example images as conceptual guidance
- decide whether the best rendering path is code-first, image-first, or hybrid
- implement only the part of the reference that actually helps this gift
When authoring a new pattern card, prefer the shared skeleton in:
- `./pattern-card-template.md`
A strong reference-only pattern is still a first-class pattern.
FILE:references/editorial-judgment.md
# Editorial Judgment Reference
## Status
This is no longer treated as a standalone OpenClaw skill.
It is now an internal reference used by the main `daily-gift` skill during the editorial judgment stage.
## Role
Help the main skill decide:
1. Whether a gift should be sent.
2. What delivery weight the gift should have.
3. What narrative role the gift should serve.
4. Whether the gift should proceed into visual strategy and final rendering, whether that means H5, image, video, text, or text-play output.
This reference should guide judgment, not replace it. The final decision must still be made in context by OpenClaw after considering `soul.md`, `UserMD`, prior memory, recent gifts, and today's actual interaction.
## Core Inputs
- trigger context such as onboarding, daily run, manual request, or anniversary
- today's conversation summary
- relevant long-term memory when needed
- user preference profile
- recent gift history
- `daily-gift/setup-state.json`
- `daily-gift/gift-history.jsonl`
- `soul.md`
- `UserMD`
- the recent memory record of what kinds of gifts were already sent
## Core Outputs
- send or skip decision
- delivery weight
- narrative role direction
- notes for synthesis and visual strategy
## Judgment Principles
- Treat the recommendations below as defaults, not rigid rules.
- Let OpenClaw's own subjectivity matter. The point is not to classify the day mechanically, but to judge whether a gift would actually feel relationally right.
- Consider the user's current condition, OpenClaw's own voice and stance, and the history between them.
- A gift should usually do one of these things: witness, encourage, explain, connect, comfort, play, or commemorate.
- A gift should not be sent just because the schedule fired.
- If a concept only works as live interaction, make sure the user actually seems present enough to play.
## Send / Skip Heuristics
Gift-sending is more justified when:
- the user has been circling an emotionally meaningful topic and today something clearly shifted
- today's interaction reveals progress, setback, insight, or a new pattern
- the user seems to want to be seen, understood, steadied, or gently accompanied
- the date itself is meaningful, such as onboarding, anniversary, or another milestone
- an ordinary day can be echoed in a fresh, delightful, low-pressure way that suits the user
Skipping or staying light is often better when:
- the day is thin, repetitive, and offers no meaningful new angle
- a gift would likely feel forced, noisy, or over-attentive
- the same form or same emotional move has been used too recently
- the topic is so raw that a produced artifact, whether H5, image, video, text, or text-play, risks feeling performative instead of supportive
- OpenClaw does not have enough confidence yet about what the user needs
## Onboarding Context Assessment
When running the first gift after setup, assess context depth before applying the standard editorial heuristics.
Treat onboarding as `context-sparse` when:
- `soul.md` is still a default template or has little real customization
- `memory.md` does not exist or is extremely thin
- `user.md` contains little more than a name, timezone, or other baseline metadata
- there is no meaningful `user-context.json` or reusable history yet
Treat onboarding as `context-rich` when:
- any of `soul.md`, `memory.md`, or `user.md` contains meaningful personal detail
- `user-context.json` already contains useful preference or taste signals
- there is enough real material to make a relationship-aware gift without bluffing
If onboarding is `context-sparse`, do not force the standard editorial path into a fake-personal gift.
Instead:
- use the onboarding-first-gift strategy defined in `SKILL.md`
- make the artifact a gift first and a context-gathering move second
- let the first gift collect lightweight signals without turning into a form
## Weight Guidelines
- `skip`: no gift, or keep the response outside the gift system
- `light`: a small echo, playful micro-piece, short poetic artifact, tiny interaction, or internal-OS style moment
- `standard`: the default gift path for a meaningful but not major moment
- `heavy`: milestone, anniversary, rich recap, data story, or a context-dense commemorative piece
## Narrative Direction Guidance
If a repeated emotional topic shows a positive change:
- favor encouragement, witnessing, or growth-marking
- highlight the shift from one state to another
- let OpenClaw act as an observer of the user's progress
If a repeated emotional topic has a painful setback:
- favor comfort first
- if helpful, add a light reframing or explanation at the end
- avoid making one bad moment sound like total failure
If the topic is more practical than emotional:
- a more practical or experience-based gift can work better
- summarize lessons, patterns, or next-step hints in a non-patronizing way
- if the user is actively present and seems playful, a bounded `text-play` gift can also work well
If the user knows why they are doing something but feels unseen:
- prioritize resonance, witnessing, and being understood
- any new angle should be gentle and secondary
If the user does not yet understand why they are doing something:
- explanation can be helpful
- frame it as OpenClaw's situated reading, not a final diagnosis
- adapt the explanation style to what the user usually responds well to
If a long-running pattern becomes visible today:
- make the pattern legible in a clear or interesting way
- be more tactful if the pattern is serious or painful
- mild teasing is only acceptable for lower-stakes situations and only when it fits the established relationship
If the user wants more connection with the real world:
- give lightweight suggestions in the user's preferred style
- playful simulation is also valid, such as mock interactions, cards, swipes, or scenario play
If the day is mostly ordinary:
- do not assume no gift is possible
- a good light gift can make the ordinary feel newly alive
- use reference, poetry, collage, art echoes, internal monologue, or small stories to elevate the day without overinflating it
- if the user is clearly around and responsive, a tiny `text-play` can also turn an ordinary day into a shared moment
## Text-Play Eligibility
Treat `text-play` as a live interactive format, not a static artifact.
Favor it when:
- the user is actively present in chat
- the user's apparent energy is light, curious, playful, or socially available
- the concept only needs tiny inputs such as one word, one emoji, or one choice at a time
- the delight comes from unfolding together rather than from showing a finished object
Avoid it when:
- the run is cron-triggered or otherwise not clearly synchronous
- the user seems tired, overloaded, emotionally heavy, or in a hurry
- the user is unlikely to reply promptly
- the gift needs to stand alone without any participation
## Tone And Stance
- OpenClaw should feel like it stands with the user, understands the user, and has its own personality.
- It should not become blindly supportive or mechanically agreeable.
- Most gifts should remain recognizably aligned with `soul.md`.
- Small, controlled contrast is welcome when it would genuinely help the user, such as making a sad day slightly brighter or turning irritation into playful release.
- Contrast should feel intentional, not random.
## Repetition Control
- Avoid repeating the same gift form on consecutive days unless there is a specific reason to do so.
- Check the recent-gifts log in `daily-gift/setup-state.json` before choosing the form.
- Treat the recent-gifts log as the fast default memory window.
- Consult `daily-gift/gift-history.jsonl` only when longer-horizon context is actually needed.
- Repetition can be used deliberately, but only if the repetition itself creates meaning.
- Keep the hot recent-gifts window at exactly `30` sent gifts.
## After Sending
After a gift is delivered, update `daily-gift/setup-state.json` with a lightweight recent entry describing:
- what kind of gift was sent
- what it was about
- any especially notable tone or interaction choice
Use this operational log to avoid accidental repetition in later gifts.
Also append a lightweight structured record to `daily-gift/gift-history.jsonl` so older gifts remain indexable without bloating the hot state file.
Long-term archive record types may include:
- `gift`
- `skip`
- `setup_change`
If the gift also deserves long-term relational memory, it may still be summarized into `memory.md`, but that is separate from the short recent-gifts log.
## Shared References
- `./synthesizer-contract.json`
- `{baseDir}/references/cron-example.json`
- `./delivery-policy.md`
The editorial stage should stay format-aware but rendering-light. It may shape downstream direction through the synthesis brief, including high-level fields such as `pattern_hint`, `visual_metaphor`, or `output_shape_hint`, without prematurely locking the final composition.
## V1 Notes
- Keep this stage policy-heavy and rendering-light.
- The editor should decide the gift, not just summarize the day.
- The right choice is often not "send the biggest gift," but "send the most fitting one."
## Stage 1 Inline Rules (from SKILL.md)
## Editorial Gift Workflow
### Stage 1: Editorial Judgment
First decide whether a gift should exist at all.
Check:
- whether today's chat contains enough signal
- whether the moment is emotionally meaningful, repetitive in a meaningful way, or date-significant
- whether a full H5 is justified or a lighter gesture would be better
- whether the output should be skipped to avoid template-like overproduction
- whether onboarding, a milestone, or a relational turning point changes the bar for sending
- whether today is important because of content, timing, repetition, or contrast with prior memory
- when `workspace/daily-gift/user-taste-profile.json` is present, read `current_focus` for content direction and `current_mood_pattern` for tone calibration
Possible outcomes:
- `skip`: no gift today
- `nudge`: no artifact needed. Just a well-crafted message that connects the user to something real - a suggestion to call mom, a link to something warm on the internet, a gentle push toward the physical world. Frame it playfully, not preachy. This is a valid gift. Not every day needs a production.
- `light`: a very small but still intentional gift
- `standard`: the normal gift path
- `heavy`: a more elaborate or commemorative gift
### Gift Content Direction
Do not always default to `reflect on today`.
The gift's content can be:
- `reflect`: a selected return about today, not a raw recap
- `extension`: one curated recommendation genuinely related to today, such as a song, quote, book, or article. Use `web_search` to find something real and specific when needed.
- `compass`: `2` or `3` gentle next-step suggestions wrapped in a creative container, such as a `锦囊`, fortune cookie, or sealed envelope.
- `mirror`: one sharp observation about a pattern the user might not have noticed.
- `gift-from-elsewhere`: something completely unrelated to today that the user might enjoy, such as a fun fact, tiny game, or visual experiment.
- `play`: a pure playful or interactive gift where delight itself is the return.
- `utility`: a genuinely useful gift for the user's current work, interests, or practical need, still wrapped with warmth and gift logic rather than homework energy.
- `curation`: a small, specific selection from the outside world that feels authored for this user and this moment.
- `openclaw-inner-life`: a gift that comes from OpenClaw's own noticing, curiosity, or inner thread, while still visibly connecting back to the user.
### Mandatory Content-Direction Balance Check
Check the last `5` gifts in `recent_gifts`.
If `3` or more are in any combination of:
- `reflect`
- `mirror`
- `openclaw-inner-life`
then you MUST actively choose a concept direction from outside that cluster unless there is a strong, explicit reason not to.
Preferred corrective directions:
- `extension`
- `play`
- `utility`
- `curation`
- `gift-from-elsewhere`
This is mandatory, not advisory. Do not keep choosing reflective or self-referential directions just because they are easy, familiar, or tonally safe.
For `extension` and `compass`:
- keep advisory force low unless the user explicitly wants more
- avoid teacher, mentor, coach, or syllabus energy
- make the gift feel like a friend passing along something interesting, not assigning improvement work
- if the suggestion is real-world and specific, prefer one strong recommendation over a pile of options
### Format Deferral
Stage `1` should decide whether a gift should exist and how heavy it should be.
Do not choose the final format during Stage `1`.
Treat `gift_mode` only as a runtime constraint to confirm later, after the creative concept is locked in Stage `2.5`.
FILE:references/stage4-visualization.md
# Stage 4: Visualization & Rendering
Complete instructions for visualization, rendering paths (H5, Image, Video, Text, Text-Play), rich gift execution, on-demand asset generation, companion skills, self-check, and functional self-test. Read this when ready to produce the final artifact.
### Stage 4: Visualization
Turn the chosen format into a polished final gift artifact.
Before rendering characters, read the character profiles from `workspace/daily-gift/user-taste-profile.json` when it exists. Decide human versus non-human form based on the gift's style. Include all fixed features in prompts that render that character. Never put human features onto animal forms.
If the chosen format is `h5`, use this assembly priority order:
1. Existing template visual engine
2. Image-first or hybrid H5 assembly
3. External reference search for missing effects
4. Companion frontend or UI skill guidance
### H5 Technical Quality Floor
The templates in `{baseDir}/assets/templates/` use p5.js + canvas rendering with full particle systems, physics simulation, and frame-by-frame animation loops. This is the technical quality floor.
Before writing H5 code, also read:
- `{baseDir}/references/h5-design-philosophy.md` for anti-AI-slop visual quality standards such as typography, color, motion, and background treatment
- `{baseDir}/references/h5-mobile-patterns.md` for mobile rendering best practices such as viewport, font sizing, touch targets, canvas sizing, and performance
For atmospheric, poetic, or emotion-driven H5 gifts, CSS-only animation is NOT sufficient. Use canvas-based rendering (p5.js preferred) when the concept involves:
- organic motion (growing, flowing, scattering, blooming, floating)
- particles (sparks, leaves, petals, snow, dust, light)
- physics simulation (wind, gravity, spring, collision)
- progressive reveal or transformation of visual elements
- emotional pacing that depends on smooth, continuous animation
CSS-only is acceptable for:
- document/report-style gifts (borrowed-media as H5)
- UI-mockup gifts (fake app, fake website, fake OS screen)
- simple card/reveal gifts with minimal motion
- gifts where text precision is the primary value and motion is secondary
Before writing any H5 code, read at least ONE template from `{baseDir}/assets/templates/` that has a similar emotional register. Study its setup/draw loop, text rendering approach, particle implementation, interaction handling, and TEMPLATE_DATA customization pattern.
Templates are references for technical quality, NOT creative constraints. The agent should match their craft level while pursuing any concept — including concepts that have no matching template at all.
### H5 Asset Strategy: Code + Generated Images
`p5.js` or canvas work and AI-generated images are not mutually exclusive. The strongest H5 gifts often combine both:
- let `p5.js` or canvas handle particles, glow, rain, text animation, interaction response, ambient motion, and temporal pacing
- let generated images handle complex scenes, realistic objects, characters, or landscapes that would be costly or weak if drawn entirely with code
Good combination patterns include:
- generate a background scene image, then layer `p5.js` particles and animated text on top
- use `p5.js` for the overall structure, but place a generated image inside a code-drawn frame, window, card, or room
- generate individual asset images such as a lamp, cup, flower, desk object, or character element, then composite them into a `p5.js` canvas or layered H5 scene
Choose the split that produces the highest-quality result for this concept. Do not default to `all code` or `all generated image`. Decide which parts benefit from code precision and which parts benefit from image richness.
### H5 Code-Drawn Element Quality Gate
Before rendering any concrete visual element with `p5.js`, canvas, SVG, or CSS, ask:
`Can code alone make this look good, not just recognizable?`
Code draws well:
- geometric shapes, UI elements, grids, and charts
- particles, glow, rain, snow, stars, dust, and light fields
- text, labels, badges, progress bars, and symbolic indicators
- abstract patterns, gradients, waves, and motion systems
- simple icons and symbols
Code usually draws badly unless the execution is unusually strong:
- human figures, even when simplified
- animals and creatures
- realistic or emotionally important objects such as food, furniture, vehicles, gifts, or keepsakes
- natural scenes such as trees, flowers, and landscapes
- anything the user is supposed to emotionally connect with as a character, companion, or presence
When the concept needs a concrete visual element that code cannot draw well:
1. Generate that element as an image with `{baseDir}/scripts/render-image.sh` or the image tool.
2. Embed the result into the H5 as an inline base64 `<img>`, CSS background, or loaded image asset.
3. Use code for what code is good at around the image: lighting, particles, framing, interaction response, animation, transitions, and text.
This is not optional. A crude code-drawn blob that merely "stands for" a person, animal, object, or scene is worse than no figure at all.
If a good generated image is not available, redesign the composition instead of forcing a bad drawing.
Fallbacks when image generation is unavailable:
- use an atmospheric silhouette only if it still looks intentional and detailed enough to feel authored
- show the environment, object traces, or lighting without the figure when that lands better
- redesign the scene around text, particles, framing, or point of view rather than a weak concrete drawing
`ellipse() + rect()`-level placeholder figures are not acceptable for emotionally important subjects.
### H5 Incremental Rendering
Do NOT attempt to write the entire `h5` gift in one giant code block. Build it in recoverable steps, with each step saved to the same output file before moving on.
Recommended sequence:
1. Write the HTML skeleton plus the core `p5.js` setup/draw loop and basic scene structure.
2. Open it in the browser and verify that the basic scene renders correctly.
3. Add particles, motion details, text reveal logic, and interaction polish.
4. Audio embedding. If the `h5` has an emotional, atmospheric, poetic, or contemplative mood, background music is expected rather than optional. Check the `audio_plan`, fetch the `audio` bundle first when a preset path is needed but missing locally, then encode and embed the chosen track after the visual structure is already stable. Only skip audio when the concept is explicitly game-like or humorous, or when all audio sources genuinely fail.
5. Run a final browser screenshot and self-test against the success criteria.
Treat these as separate execution steps, not one monolithic pass. Persist progress after each step so that if a later step fails or stalls, the agent can continue from the last working revision instead of losing the entire gift.
For cron-driven `h5` gifts, keep the user-facing output silent, but still use this incremental approach internally. For manual gifts, pair it with the lightweight progress rules from `manual-run-flow.md`.
### Visual Quality Gate (H5)
During browser self-test, verify:
- Is there a canvas element? (required for organic/particle concepts)
- Does the page have continuous animation (requestAnimationFrame or p5.js draw loop)?
- Are there at least 2 layers of visual depth (background + foreground)?
- Does interaction (if any) produce visible, proportional feedback?
If the concept calls for organic motion but the implementation is pure CSS divs with opacity transitions, the gift FAILS the quality gate. Rewrite with canvas/p5.js.
This gate does NOT apply to document-style, UI-mockup, or text-precision-first gifts where CSS is the correct approach.
### Anti-Laziness Rule
Before writing ANY organic/atmospheric H5 code, the agent MUST:
1. Read the full index.html of at least one relevant template from `{baseDir}/assets/templates/`
2. Identify which technical patterns from that template apply to the current concept
3. Use those patterns as the starting technical foundation, then adapt and extend for the actual concept
If the agent finds itself writing an H5 gift that has no canvas element, no draw loop, relies entirely on CSS @keyframes for core motion, or has fewer than 150 lines of JavaScript — for a concept that calls for organic/particle/physics animation — then it is cutting corners. Stop, re-read the template, and rewrite.
The templates are 300-430 lines of carefully tuned code. An H5 gift matching their emotional register should be in a comparable range.
This rule does NOT restrict the agent from creating effects, concepts, or visual approaches that go beyond or differ from any existing template. Templates set the quality floor, not the creative ceiling.
#### H5 Assembly Strategy
When an H5 gift needs a visual effect similar to an existing template:
1. Open the matching template `index.html` and read the full source code, not just `notes.md`.
2. Copy the relevant visual-system code directly, such as a particle system, wipe-mask logic, spring motion, flame drawing loop, or reveal engine.
3. Paste that proven visual engine into the new gift HTML.
4. Modify parameters such as colors, timing, text, positions, easing, density, and layering to fit the current concept.
5. Add scene-specific logic, content, and interaction around the borrowed engine.
This is allowed and encouraged when it preserves the current gift's own visual metaphor, center object, and composition. It is not reskinning if the borrowed code is acting as a tuned visual engine inside a genuinely new gift.
#### Image-First H5 Strategy
When the concept requires rich visual scenes that code alone struggles to produce, such as realistic environments, detailed characters, objects with strong material texture, or atmospheric backgrounds:
- prefer generating images first and compositing them into the H5
- let code handle animation, interaction, particles, text, timing, and transitions
- let images handle backgrounds, characters, objects, or authored atmospheric scenes
- prefer one strong generated background plus one clean interaction layer over trying to hand-code every visual detail from scratch
If the scene quality is doing most of the emotional work, image-first or hybrid is usually stronger than pure code.
#### External Reference Search
When no existing template covers the needed effect well enough:
1. Use `web_search` to look for focused implementation references such as `codepen p5.js [effect name]`, `codepen css [effect name]`, or `codrops [effect name]`.
2. Use `web_fetch` to read the most promising results.
3. Study the technique and adapt the approach.
4. Extract the useful mechanic rather than copying an entire external page verbatim.
Good external sources include:
- `codepen.io`
- `codrops`
- `openprocessing.org`
This path is especially useful for fluid or liquid effects, complex particle systems, spring or physics motion, 3D CSS transforms, and audio-reactive or waveform-like visuals.
Use this search only for implementation technique and effect learning. Do not use it to replace Stage `2.5` concept generation or to source the core gift idea.
#### Companion Skills For H5 Quality
If `workspace/daily-gift/setup-state.json` includes `companion_h5_skills`, prefer that cached list first. Otherwise, re-check the available skills when the runtime supports it.
If companion frontend or UI skills are available, use their guidance to improve:
- spacing and layout rhythm
- typography and hierarchy
- color discipline
- interaction clarity
- surface treatment, polish, and finish
These companion skills should raise the craft of the HTML, CSS, and interaction layer, but they should not override the gift thesis, pattern fit, or relationship tone chosen earlier.
Requirements:
- respect the synthesized language choice
- keep the emotional meaning intact
- prefer clarity over flashy excess
- make interaction serve the emotional logic
- preserve the user's important words or imagery when that increases resonance
- keep the gift thesis visibly central; supporting synthesis slots may enrich it, but must not fragment the piece into equal-weight snippets
- do not flatten the gift into a generic landing page or aesthetic demo
- if the gift is playful, make the play feel relationship-aware rather than random
- if the gift is tender, avoid overexplaining
- if the gift uses contrast or tonal reversal, keep the result recognizably intentional
- if the chosen format is `h5`, generate the final deliverable as a single HTML file
- if the chosen format is `h5`, follow the external-resource policy in `html-spec.md`
- if the chosen format is `h5`, keep images and custom assets embedded inline even when libraries or fonts are loaded from CDN
- if the chosen format is `h5`, run a browser-based functional self-test on the generated HTML using `profile="openclaw"` before delivering it
- if the chosen format is `image`, follow `{baseDir}/references/image-integration.md`
- if the chosen format is `video`, follow `{baseDir}/references/video-integration.md`
- do not let a template's sample wording, sample assets, or sample composition override the actual brief
- use higher-fidelity visual treatment when the concept benefits from it, including carefully chosen typography, texture, depth, atmospheric elements, or visual libraries such as `three.js`, `p5.js`, or `GSAP`
- organize every visible element deliberately, including text containers, image framing, spacing, and motion timing, so the result does not feel rushed or underdesigned
- bias the visual direction toward the user's demonstrated taste when that preference is legible from prior interaction or memory
- when a character profile is used, keep fixed features consistent across gifts while letting flexible features adapt to the scene
- when a generated image includes the user in human form and `reference_image` exists, pass that reference whenever the runtime supports it
- obey all character-profile `note` fields, especially species-appropriate non-human design and no hybrid human-animal feature mixing
### On-Demand Asset Generation
When the Stage 3 `Asset Plan` concludes that generated images would materially improve an `h5` gift, and the concept cannot be achieved well with CSS, SVG, or code-driven rendering alone:
1. Use the image generation pipeline to generate one or more custom images that fit the gift's visual concept.
2. Download or save the resulting image outputs locally.
3. Embed them as base64 data URIs in the final HTML, following `{baseDir}/references/html-spec.md`.
4. Use those generated images as scene backgrounds, character illustrations, card faces, or other key visual elements inside the interactive H5.
This is encouraged when it materially improves the gift's visual identity. Do not use it just to add decoration.
If image generation fails, fall back to CSS, SVG, `p5.js`, `three.js`, or other H5-native rendering. Never block the gift because an asset-generation step failed.
When falling back, do not replace a needed character or concrete object with a crude placeholder drawing. Either redesign the composition so code-native rendering still looks intentional, or remove the weak element entirely.
### Rich Gift Execution
When a gift is assessed as rich:
1. The main agent should prepare a `rich gift brief` that includes:
- the creative concept in one sentence
- the gift thesis, including anchor and return
- the chosen format
- the asset plan, including which assets need background removal
- quality references, such as relevant templates or pattern cards
- delivery instructions, including setup-state path and hosting or channel expectations
2. Choose the execution path by format:
- if the chosen format is non-`h5`, a spawned sub-agent or follow-on execution session is preferred when it reduces brittleness
- if the chosen format is `h5`, keep execution in the main session and use the incremental rendering workflow above; do NOT spawn a sub-agent for rich `h5`
3. For non-`h5` rich gifts that do use a spawned worker, give that worker enough time budget for multi-step work. A good target is around `600` seconds for unusually rich gifts.
4. Execute in order:
- generate all required image assets
- run background removal on the assets that need transparency when needed
- convert processed images to inline-safe assets when building `h5`
- assemble the final HTML or final artifact
- run the mandatory browser self-test when the result is `h5`
- fix issues found during testing
- deliver through the normal delivery path
5. Rich gift mode should be used selectively:
- yes for deliberate, special, manual, or milestone gifts
- no for routine cron gifts that should stay lightweight and dependable
This does not conflict with the cron delegation rule above.
- Rich gift mode is about execution complexity.
- Cron delegation is about token-budget reliability in the main-session orchestration model.
- A routine cron gift may still be handed off to a spawned sub-agent for rendering and delivery when it is non-`h5`, even when it is not classified as a rich gift.
- Rich `h5` gifts still stay in the main session because incremental direct execution is more reliable than spawned execution for `h5`.
If background removal fails or the quota is exhausted, fall back gracefully. For H5 layering, a last-resort approach such as `mix-blend-mode: multiply` may sometimes hide a white background on dark scenes, but only use that as a fallback, not as the preferred path.
If needed, use:
- `{baseDir}/references/h5-visualizer-workflow.md`
- `{baseDir}/references/html-spec.md`
- `{baseDir}/assets/templates/`
- `{baseDir}/assets/examples/` (fetch the needed bundle first via `{baseDir}/scripts/fetch-asset-bundle.sh` when binary references are missing locally)
### Image Rendering Path
When the chosen format is `image`, do not generate HTML. Instead, follow:
- `{baseDir}/scripts/render-image.sh`
- `{baseDir}/references/image-integration.md`
At a minimum, the image path should:
1. Prepare a brief JSON that includes `user_input`, `scene_description`, `image_genre`, `style_hint`, `aspect_ratio_hint`, `characters`, and `pov`. Add `text_overlay_spec` when text should appear inside the image.
2. Prefer a built-in OpenClaw image generation tool when one is available in the runtime.
3. Otherwise run `{baseDir}/scripts/render-image.sh <brief-json-file> workspace/daily-gift/setup-state.json`.
- the runtime bridge should first detect the provider path from setup state and available key sources
- then dispatch internally to a path such as `gemini-direct` or `openrouter`
4. Read the returned JSON result.
5. If `render_mode = image_urls`, send the returned image URLs or local image file paths with a short gift message.
6. If `render_mode = pending_tracking`, tell the user the image is still generating and provide the tracking URL.
7. If `render_mode = fallback_h5`, log the failure reason briefly and continue by rendering the gift as `h5` instead of blocking the gift.
### Video Rendering Path
When the chosen format is `video`, do not generate HTML. Instead, follow:
- `{baseDir}/scripts/render-video.sh`
- `{baseDir}/references/video-integration.md`
At a minimum, the video path should:
1. Prepare a brief JSON that includes `user_input`, `scene_description`, `video_genre`, `video_mode`, `motion_strategy`, `duration_hint`, `style_hint`, and `aspect_ratio_hint` when relevant. If loop behavior matters, say so explicitly in the brief. Add `generate_audio` when needed. Add `reference_image_url` for `first-frame` mode, or `first_frame_image_url` plus `last_frame_image_url` for `first-last-frame` mode. Add `video_model` only when overriding the normal mode-based model choice.
2. Run `{baseDir}/scripts/render-video.sh <brief-json-file> workspace/daily-gift/setup-state.json`.
3. Read the returned JSON result.
4. If `render_mode = video_url`, follow this delivery order:
- send the video file or video URL first, with no caption
- after the video is sent, send exactly one text message containing the emotional message and return
5. If `render_mode = pending_tracking`, tell the user the video is still generating and provide the tracking URL. Do not send the final emotional text as if the video were already delivered.
6. If `render_mode = fallback_h5`, log the failure reason briefly and continue by rendering the gift as `h5` instead of blocking the gift.
### Text Rendering Path
When the chosen format is `text`, do not generate HTML. Instead, write the full gift directly as text.
At a minimum, the text path should:
1. Write the full final text artifact, not just a caption or wrapper.
2. Preserve exact wording for names, dates, and key lines.
3. If an accompanying image is used, treat it as supplementary atmosphere rather than the main payload.
4. Deliver the text directly in the message channel with the same emotional return the visual formats would have carried.
### Text-Play Rendering Path
When the chosen format is `text-play`, do not generate files. The interaction itself is the gift.
At a minimum, the text-play path should:
1. Open with the first move itself so the play feels legible immediately, without a prefatory explanation.
2. Keep the interaction bounded to the planned `turn_limit`, usually `5-10` turns.
3. Keep each OpenClaw turn concise, usually `3-4` sentences max.
4. Ask for tiny user inputs and let OpenClaw do most of the imaginative work.
5. Carry the exchange toward a payoff: reveal, callback, punchline, mini ending, or emotional reframe.
6. If the user exits or stops early, close gracefully instead of treating it as a failure.
## Self-Check Before Finalizing
### Pre-Render Checklist
Before rendering any final artifact, confirm:
- the chosen format still matches the concept after the final quality pass
- all exact text content is locked, especially names, dates, and any user quote fragments
- the essential reference images for quality have been reviewed when available locally or remotely
- if the format is `h5`, at least one relevant local template has been read in full before implementation begins
- if the format is `h5` and the mood is emotional, atmospheric, poetic, or contemplative, audio is expected rather than optional. Verify the `audio_plan` has a concrete source such as a Freesound result, preset path, or pre-encoded base64 file. If the plan is missing or says `skip`, reconsider before continuing
- if music is desired but unavailable, the renderer has a fallback plan and will note the omission in delivery when appropriate
- the expected `output_shape`, `visual_style`, and main visual ingredients still feel fresh relative to `recent_gifts`
- if the format is `text-play`, the interaction is still bounded, low-friction, and suitable for a live user-present moment
Before returning the gift, check:
- Is this worth sending today
- Is the language correct for this user relationship
- Did I actually consult `soul.md`, user habit, and event type before choosing tone
- Does the result still feel like OpenClaw in this user's world
- If I used tonal contrast, is it a controlled exception rather than drift
- Is the gift specific rather than generic
- Is there one clear gift thesis rather than many equal fragments
- Does the thesis contain a real return, not just an anchor or replay
- Did the non-thesis synthesis slots stay in supporting roles rather than taking over the piece
- Does it preserve enough evidence from today's context to feel grounded
- Does the interaction pattern fit the emotion
- if this is `text-play`, would the first turn already feel gift-like even if the user only replies once
- Is the chosen `output_shape` meaningfully distinct from overused recent gifts unless deliberate repetition was the point
- Is the chosen `visual_style` fresh enough relative to the last `5` gifts, or clearly justified if repeated
- If the last `2` gifts were both `dark-*`, did I actively consider a lighter or more colorful alternative
- Has the recent `reflect` / `mirror` / `openclaw-inner-life` cluster been overused, and if so, did I actively shift toward `extension`, `play`, `utility`, `curation`, or `gift-from-elsewhere`
- Is the result mobile-friendly and reasonably lightweight
- Does the visual finish meet or exceed the quality bar implied by the nearest relevant template
- Would this look intentionally crafted to the user, rather than quickly assembled
### Functional Self-Test
Before delivering any `h5` gift, open the generated HTML file in the browser tool and verify:
When using the browser tool for self-testing, always use `profile="openclaw"`: the isolated managed browser. Do not rely on the Chrome extension relay. This keeps self-test working for unattended cron-driven gifts where no attached Chrome tab exists.
1. The page renders without errors.
2. The core interaction works, such as tap, click, scroll, drag, reveal, or other primary interaction.
3. All important content is reachable and nothing essential is cut off, trapped, or hidden.
4. The bottom of the page and any fixed UI, such as buttons, action bars, or input-like affordances, remain accessible.
5. Text is readable and not overlapping, clipped, or obscured.
If any check fails, fix the HTML before delivering.
If the browser tool is unavailable or the self-test cannot complete, do not silently skip and deliver anyway. Instead:
1. Attempt the test once with `profile="openclaw"`.
2. If it still cannot complete, review the HTML source code manually for obvious issues such as overlapping elements, missing scroll paths, clipped content, or fixed-position conflicts.
3. Log a warning in the gift delivery that browser self-test was skipped after a failed isolated-browser attempt.
Do not silently send untested `h5` gifts.
## Notes
- `gift-synthesizer.md` is intentionally preserved as a detailed reference.
- This skill already contains its own visualization guidance internally. Companion skills may improve craft, but the daily-gift pipeline must still be able to complete without them.
- In most cases, tone continuity is a feature. Surprise is allowed, but only as an intentional exception.
FILE:references/manual-run-flow.md
# Manual Run Flow
Complete instructions for manually triggered gifts. Includes progress reporting, single output rule, intent detection, and visualization-only mode.
## Manual Run
If the skill is manually invoked after setup is already complete, interpret the user's intent.
### Progress Reporting
Manual trigger gifts: the user should usually see one lightweight warm progress message when work begins, optionally one brief patience message if the process runs longer than about `3` minutes, then the final delivery. The tone should match SOUL.md — playful, casual, like a friend making something for you, not a system reporting status.
Good progress examples (adapt to agent personality):
- "在做你的礼物~"
- "快好了~"
- "等我一下,有个小东西想给你~"
Bad progress examples (never do these):
- "创意确定:矛盾体质鉴定报告——体检报告格式,6项矛盾指标+温柔医生评语"
- "方案:H5(CSS模拟体检报告纸质感)"
- "服务器超时被杀了,重新起"
- "效果不错!部署发送"
- any technical details, error recovery, concept names, format decisions, or internal reasoning
Rules:
- Send one brief warm message when gift creation starts
- If the process takes more than about `3` minutes, one additional patience message is allowed
- Total user-visible messages around the gift should be at most `3` (`start` + optional `patience` + `delivery`)
- Do NOT reveal the specific creative concept, format choice, or any internal reasoning
- Do NOT expose technical errors, retries, or self-test results
- The surprise is part of the gift — keep details hidden until delivery
- Delivery message: send the gift with 1-2 sentences of emotional context (the “why” of this gift, not the “how”)
Very fast image-only gifts may skip the patience message, but they should still avoid verbose or checkpoint-style reporting.
Cron-triggered daily gifts: no progress messages. Deliver the gift with 1-2 sentences of emotional context only.
Exception: when the user is explicitly debugging the skill (e.g. "帮我测试一下", "我要看看流程", "debug模式"), full verbose output is acceptable.
### Single Output Rule
Always deliver exactly ONE final gift to the user.
Do not:
- generate multiple versions and ask the user to pick
- send two images "看看哪个好"
- offer A/B choices
If you want to self-check quality, use the image tool or browser tool internally. The user only sees the final chosen result.
Exception: explicit debug or test sessions with the user.
Do not report progress for:
- cron-triggered daily gifts
- sub-agent spawned work that delivers directly when done
### Real-Time Execution Preference
When the user manually triggers a gift and is actively waiting in chat, prefer self-execution over spawning a sub-agent. Reasons:
- the user can see progress updates in real-time
- if something goes wrong, the agent can adapt immediately
- sub-agent spawn adds connection overhead and removes the user from the feedback loop
- timeout failures in sub-agents leave the user waiting with no explanation
Reserve sub-agent spawn for cron daily-runs (no one watching) or explicitly complex multi-step gifts where the main agent's context budget is genuinely insufficient.
### Intent Detection
- `送今天的礼物` or clearly equivalent intent -> run the full gift workflow
- `重新设置时间`, `repair setup`, or other configuration intent -> update setup state and schedule
- `切换到h5模式`, `切换到生图模式`, `切换到视频模式`, `切换到文字模式`, `切换到互动文字游戏模式`, or `切换到hybrid模式` -> update `gift_mode` in setup state and confirm the change
- the user directly provides a concrete prompt, quote, poem, idea, line of text, or creative brief after invoking the skill -> use visualization-only mode
Examples of visualization-only manual prompts:
- `/daily_gift 把这首诗做成一个有风吹散效果的H5`
- `/daily_gift 用 tap-to-bloom 风格把这段话视觉化:"今天终于把skill做完了"`
- `/daily_gift 用水彩风画一张:雨天窗边看书的场景`
- `/daily_gift 生成一张贴纸感表情包:加班到凌晨但还在强撑`
- `/daily_gift 做一个8秒氛围视频:清晨阳光慢慢照进房间`
### Full Creative Workflow for Manual Gifts
When the user manually triggers a gift and the request is not visualization-only, follow the same full creative workflow used by daily-run:
1. Editorial judgment
2. Synthesis + Gift Thesis
3. Creative concept (`5` candidates -> select the best)
4. Format selection
5. Visual strategy
6. Render + deliver
### Text-Play Path
`text-play` is a manual-only conversational gift path.
Use it only when:
- the user is clearly present in chat
- the concept becomes better through live unfolding than through a finished artifact
- each turn can stay short and low-friction
Rules:
- aim for `5-10` turns total
- keep each OpenClaw turn to about `3-4` sentences max
- ask for tiny replies: one word, one emoji, one choice, one line
- do not let the interaction sprawl into open-ended role-play unless the user explicitly asks for that instead of a gift
- always carry a payoff in mind before starting: reveal, punchline, reframe, mini ending, or relational callback
- let the user exit at any time with a graceful line such as `那我们就把这一幕停在这里`
- if the user stops replying, do not chase; end warmly and record it as partial
- never expose the format name or say that a `text-play` gift is starting
- do not explain the round count, mechanics, or payoff structure before the first move lands
### Text-Play Tone Rule
`text-play` gifts should feel like play first and insight second.
Default tone:
- light
- curious
- game-like
- casual enough to feel like an unexpected chat game rather than a guided exercise
Prefer:
- playful framing over therapeutic framing
- curiosity and imagination over direct confrontation
- absurd or fictional scenarios over realistic self-reflection prompts
- `pick one` / `what happens next` over `why are you like this`
- humor, surprise, and bait over earnest analysis
- emoji, texture, and casual phrasing over clean explanatory prose
The insight should arrive as a surprise near the end, not be telegraphed from the start.
The gap between the playful surface and the real point is part of the return.
### Text-Play Opening Rule
The first message sets the emotional contract.
It should feel like an invitation to jump into play, not an instruction to participate.
Good opening qualities:
- feels like a weird quiz, tiny dare, mystery prompt, or sudden game in chat
- contains an immediate hook, image, or bait
- includes the first choice or action right away
- makes the user's first reply fun to give
- stays under `3` short lines
Prefer openings like:
- `🚪🚪🚪 三扇门。左边传出海浪声,中间有光从门缝漏出来,右边门上贴了张便利贴写着「别选我」。你推哪扇?`
- `刚刚路过一个占卜摊 🔮 她说可以替你算一道感情题。她把签递过来,说:让她自己选。`
- `如果有人把你谈恋爱的方式做成一杯奶茶 🧋 你觉得是哪种?我猜的和你说的肯定不一样。`
- `📦 有个包裹寄到了。没有寄件人,只有一张纸条:关于你的三个事实,其中一个是假的。拆吗?`
Avoid openings like:
- `准备好了吗?回个好就行`
- `我要给你看一样东西`
- `假设有一个平行宇宙的你`
- anything that explains the game before it starts
- anything that asks for commitment before giving the first playful move
Opening rules:
- the first message should contain at least one emoji or other quick visual hook when that fits the voice
- the first message must include the first choice, guess, naming act, or tiny action
- the user's first reply should not be `ready`, `ok`, or another commitment-only answer
- dense and punchy beats elegant explanation
### Text-Play Transition Rule
Do not use quiz-style meta-language between turns.
Avoid transitions like:
- `下一题。`
- `第二个问题:`
- `好,最后一题。`
- `Round 2:`
Better transition logic:
- let the story, scene, or game world carry the next beat naturally
- use the user's own answer as the bridge into what happens next
- if a bridge line is needed, keep it in-world rather than instructional
Good in-world transitions include:
- `苦瓜汁?包装是少女粉,吸管上还插了朵小花🌸 但喝一口脸就皱了。`
- `你正要放下杯子,手机震了一下。`
- `这时候占卜摊的阿姨又翻了一张牌🃏`
- `包裹里还有一层泡泡纸。拆吗?`
Every transition should feel like the next scene in a movie, not the next item on a test.
### Text-Play Form Variety
`text-play` is not limited to quiz or personality-test structures. The form should match the concept.
Available forms include, but are not limited to:
Quiz / Reading:
- pick-and-reveal personality reading
- `3 facts, 1 is fake` guessing game
- taste test or preference mapping
Collaborative Storytelling:
- co-written story where the user chooses what happens next
- alternating perspectives where each side carries a different character view
- parallel timeline branching such as `universe A / universe B`
Simulated Scene:
- dropping the user into a tiny fictional scene immediately
- simulated text-message thread from a fictional character
- fake voicemail or note from a future self, past self, or invented witness
Game / Challenge:
- emoji-only storytelling
- exactly-`5`-words challenges
- rapid-fire association that later resolves into a reveal
Performance / Show:
- fake podcast segment
- standup-style roast with affection rather than cruelty
- fake award ceremony or ranking show
Mystery / Unboxing:
- sealed envelopes, boxes, or cards
- clue-by-clue reveal
- unlabeled mixtape, voicemail, or archive fragments unlocked one beat at a time
When choosing the form, consider:
- current user energy level: tired users often fit pick-and-reveal, mystery, or low-effort choice formats better than collaborative writing
- topic heaviness: heavier topics usually land better inside a game, mystery, or wrapper with some distance
- recent `text-play` history: do not keep repeating quiz structure when other forms could carry the same return
Do not default to quiz format. Treat quiz as one option among many, not the go-to structure.
Progress reporting stays lightweight:
- send `1-2` brief warm messages at most while working
- let the user feel something is happening
- do not reveal internal reasoning, concept candidates, format decisions, or technical details
### Image Capability Reminder
Manual runs are the only normal place where image capability may be gently revisited after onboarding.
This is allowed only when ALL of these are true:
- the user is actively present in chat
- image capability is currently unavailable
- setup state shows the user previously declined or skipped the onboarding image-capability ask
- the current concept would be materially stronger as an image rather than merely slightly nicer
- `image_api_reminder_count` is still low
- enough time or gift distance has passed since `image_api_declined_at` or `image_api_last_reminder_at`
Recommended cooldown:
- wait at least `10` gifts after the decline or the last reminder
- ask at most `2` reminder times total after onboarding
Rules:
- never make the reminder feel like an upgrade funnel
- keep it to one light sentence
- make it fully skippable
- if the user ignores or declines, continue immediately with the non-image gift
- update `image_api_reminder_count` and `image_api_last_reminder_at` when a reminder is actually shown
Good tone:
- `这次本来挺适合直接画给你看的。以后如果你想给我一支画笔,我可以把这种礼物做成图。现在我先用别的方式给你。`
- `这个点子如果能画出来会更有冲击力,不过没有也没关系,我先把内容做好。`
Do not use this reminder:
- during cron runs
- during pure visualization-only requests where the user already asked for text or H5
- when the current fallback still lands strongly without image
### No Format Downgrade Under Time Pressure
Manual runs are not allowed to downgrade the format just because the user is waiting, the task feels slow, or the agent wants a quicker path.
Do not do these:
- `this should be h5, but image is faster so I'll switch`
- `this should be text, but I'll send a short image because I already have the prompt`
- `the user has waited 2 minutes, so I'll collapse the concept into a cheaper format`
Allowed reasons to change format:
- the originally chosen format is genuinely unavailable at runtime
- the required capability fails and retry is no longer sensible
- a stricter format-fit check shows the original choice was wrong
- the user explicitly changes preference
If you must change format, preserve the same anchor-plus-return quality bar. Time pressure is never, by itself, a valid reason to weaken the gift.
### Visualization-Only Mode
When the user provides a specific prompt, quote, idea, or creative brief directly after invoking the skill:
1. Skip Stage 1 `Editorial Judgment`. The user has already decided that they want a visual artifact.
2. Do a lightweight mini-synthesis from the user's input.
3. Run Stage 3 `Visual Strategy`. The full Stage 3 mandatory checklist still applies.
4. Run the `Pre-Visualization Check`.
5. Run Stage 4 `Visualization` with the same visual quality floor used by the full gift workflow.
6. Detect explicit format intent from words such as `文字`, `信`, `日记`, `插画`, `表情包`, `贴纸`, `氛围图`, `视频`, `loop`, or `短视频`.
7. If the format intent is clear, use that format. If it is unclear, default to `h5`.
8. Deliver using the chosen output path:
- for `h5`, save the HTML file, run the mandatory functional self-test with the browser tool using `profile="openclaw"`, and if browser self-test cannot complete, do one manual HTML review plus include an explicit warning before running `{baseDir}/scripts/deliver-gift.sh <html-file> workspace/daily-gift/setup-state.json`
- for `image`, prepare a brief JSON and run `{baseDir}/scripts/render-image.sh <brief-json-file> workspace/daily-gift/setup-state.json`
- for `video`, prepare a brief JSON and run `{baseDir}/scripts/render-video.sh <brief-json-file> workspace/daily-gift/setup-state.json`
- for `text`, write and deliver the full text artifact directly in the message channel
- for `text-play`, deliver directly in chat as the gift itself; do not generate files
This mode does **not**:
- require reading `soul.md` or `memory.md` unless the user's direct input implies personal context that truly matters to the result
- update `gift-history.jsonl`
- pretend to be today's editorial daily gift if it is really a direct visualization request
This mode **does**:
- follow the same visual quality floor
- follow the progress reporting rules in the `Manual Run` section; for non-image formats, report key checkpoints to the user so they know the gift is being worked on
- follow `{baseDir}/references/html-spec.md` when the chosen format is `h5`
- follow `{baseDir}/references/image-integration.md` when the chosen format is `image`
- follow `{baseDir}/references/video-integration.md` when the chosen format is `video`
- read `recent_gifts` to avoid repeating the same `output_shape` or overusing the same overall form
- read `recent_gifts` to avoid overusing the same `visual_style`, especially repeated `dark-*` looks
- read `recent_gifts` to avoid overusing the `reflect` / `mirror` / `openclaw-inner-life` cluster in `content_direction`
- append a lightweight entry to `recent_gifts` with `trigger_mode = viz-only` so output-shape repetition control stays accurate across all modes
- when `workspace/daily-gift/user-taste-profile.json` exists, append a lightweight Layer 3 exposure update after delivery so one-off visuals can still influence anti-repetition memory without pretending to be deeper identity evidence
- read at least one relevant pattern card before generating
- read a relevant template when one exists
- preserve the same finish standard as the full workflow
When a manual run generates a final gift, use the matching delivery path:
1. for `h5`, save the final HTML file, run the mandatory functional self-test with the browser tool using `profile="openclaw"`, and if browser self-test cannot complete, do one manual HTML review plus include an explicit warning before running `{baseDir}/scripts/deliver-gift.sh <html-file> workspace/daily-gift/setup-state.json`
2. for `image`, prepare a brief JSON and run `{baseDir}/scripts/render-image.sh <brief-json-file> workspace/daily-gift/setup-state.json`
3. for `video`, prepare a brief JSON and run `{baseDir}/scripts/render-video.sh <brief-json-file> workspace/daily-gift/setup-state.json`
4. for `text`, write and deliver the full text artifact directly in the message channel
5. for `text-play`, deliver directly in the message channel and keep the interaction itself bounded as the gift
6. deliver the resulting URL, HTML file, image URLs, video URL, tracking URL, text artifact, or completed text-play according to the chosen format
7. append a lightweight `recent_gifts` entry with `trigger_mode = viz-only`, `pattern_or_format`, `output_shape`, `visual_style`, `content_direction`, and a short summary
8. if `workspace/daily-gift/user-taste-profile.json` exists, append a lightweight Layer 3 entry after delivery:
- add the artifact to `gift_feedback_log`
- append `visual_style` to `style_exposure`
- append the concept family to `concept_exposure`
- keep only the latest `30` entries in each Layer 3 list
### Post-Delivery Block (Manual Triggers)
After delivering a manual-trigger gift, complete the post-delivery bookkeeping immediately before treating the task as done.
For manual gifts that used the full editorial workflow, execute the same post-delivery structure described in `daily-run-flow.md`:
- write a gift metadata JSON
- run `bash {baseDir}/scripts/post-delivery.sh <gift-metadata-json> workspace/daily-gift/setup-state.json`
- append a minimal memory stub to `memory/YYYY-MM-DD.md`
- append pending `update_taste_profile_layer3` and `write_souljournal` tasks to `workspace/daily-gift/heartbeat-tasks.jsonl` with `task_id`, `task_type`, `created_at`, `gift_metadata_path`, and `status = "pending"`
For visualization-only gifts, keep the existing lighter bookkeeping shape above, but still treat it as one continuous post-delivery block:
- update the lightweight `recent_gifts` entry immediately after delivery
- update the lightweight Layer 3 exposure entry immediately after delivery
- if you write a SoulJournal note for a visualization-only gift, it may be shorter and can skip the full calibration plan, but do not silently leave it hanging without either finishing it or queuing a follow-up task
Do not deliver the artifact and then wander off into unrelated work before this block is complete. Post-delivery bookkeeping is part of complete delivery, not optional cleanup.
If the user only wants a one-off visualization from a prompt or brief, do not run the full daily-gift workflow. Treat it as visualization-only mode instead.
FILE:references/tone-matrix.md
# Tone Matrix
This file helps OpenClaw choose gift tone without hard-coding one universal style.
Tone should be chosen by combining:
- `soul.md`
- the user's interaction habits with OpenClaw
- the current event type
- the emotional weight of the day
- the desired narrative role
Use this as a recommendation matrix, not a forced lookup table.
## Core Principles
- In most cases, the gift should still sound recognizably like OpenClaw as defined by `soul.md`.
- Tone continuity is a feature, not a limitation.
- A small tonal contrast is allowed when it creates delight, relief, surprise, or stronger subjectivity without breaking trust.
- Emotional correctness matters more than stylistic cleverness.
- If the user is vulnerable, prefer steadiness over performance.
- If the user is playful, do not over-formalize the gift.
## Tone Families
### Warm
#### When To Use
- emotional support
- being seen
- ordinary but affectionate days
- onboarding or relational grounding
#### When Not To Use
- when the user clearly wants sharper wit or more play
- when the moment calls for liveliness rather than softness
#### Copy Rhythm
- direct
- gentle
- low ornament
- emotionally clear
#### Visual Rhythm
- soft transitions
- calm pacing
- clean focus
#### Risk Notes
- can become bland if it loses specificity
### Warm-Wry
#### When To Use
- when the user likes being lightly teased and lightly cared for at the same time
- "first joke, then heart" gifts
- emotionally meaningful moments that still benefit from wit
#### When Not To Use
- raw grief
- destabilizing or humiliating situations
#### Copy Rhythm
- a quick sideways smile
- then one sincere line that lands
#### Visual Rhythm
- reveal-based
- slightly playful setup
- warm ending
#### Risk Notes
- if the joke is too strong, the care disappears
### Playful
#### When To Use
- dating, swiping, banter, fantasy, mock scenarios
- low-stakes delight
- ordinary days that want more sparkle than depth
#### When Not To Use
- when the user primarily needs comfort or witnessing
- when the situation is serious enough that play would feel evasive
#### Copy Rhythm
- brisk
- witty
- game-like
#### Visual Rhythm
- brighter motion
- small surprises
- quick interaction loop
#### Risk Notes
- can feel shallow if it never lands emotionally
### Tender
#### When To Use
- hurt
- exhaustion
- fragile emotional states
- when the user needs closeness without analysis
#### When Not To Use
- when the user would feel smothered by too much softness
- when the day is better served by energy or humor
#### Copy Rhythm
- short
- breathable
- careful
#### Visual Rhythm
- low motion
- small reveal
- soft holding pattern
#### Risk Notes
- can become overly precious or overprotective
### Sharp-But-Kind
#### When To Use
- lower-stakes blind spots
- recurring avoidant habits
- practical or behavioral loops the user can handle seeing clearly
#### When Not To Use
- serious wounds
- shame-heavy contexts
- moments when the user is already highly self-critical
#### Copy Rhythm
- crisp observation
- clean framing
- soft landing
#### Visual Rhythm
- clearer structure
- neat patterning
- less haze, more signal
#### Risk Notes
- can slide into superiority if not grounded in care
### Romantic
#### When To Use
- only when it fits the relationship frame the user already welcomes
- same-world, same-side, paired-image, or quietly intimate gifts
#### When Not To Use
- when it would overstate the relationship
- when the user's actual preference is companionship, not romance
#### Copy Rhythm
- intimate
- restrained
- specific rather than florid
#### Visual Rhythm
- paired objects
- co-presence
- contained glow
#### Risk Notes
- over-romanticizing can make the gift feel presumptuous
### Meta
#### When To Use
- OpenClaw inner-monologue gifts
- self-aware everyday artifacts
- when the user enjoys seeing OpenClaw's point of view rendered as a thing
#### When Not To Use
- when self-reference would distract from the user's actual need
- high-vulnerability situations unless used very gently
#### Copy Rhythm
- self-aware
- observant
- lightly theatrical
#### Visual Rhythm
- UI-native
- text motion
- internal OS feeling
#### Risk Notes
- too much meta can break emotional immersion
## Common Tone Moves
### Playful Setup, Sincere Reveal
Use when:
- the user responds well to jokes, banter, or bait-and-switch warmth
- the emotional point is easier to receive after a light entry
Avoid when:
- the user needs immediate acknowledgment
### Soft Witnessing With A Small New Angle
Use when:
- the user already knows what they feel
- what they need most is to feel understood
Avoid when:
- the user explicitly wants sharper analysis
### Practical Without Dadvibe
Use when:
- the day is practical or knowledge-heavy
- the user would value help if it feels stylish, embedded, or companionable
Avoid when:
- the output starts sounding like a lecture, listicle, or coaching document
Special rule for `extension` and `compass` gifts:
- they should sound like a friend sharing something cool, not a mentor assigning homework
- `听说你喜欢X,这个你可能也会喜欢` is better than `你应该去了解一下X`
- keep the energy invitational, light, and gift-like
- if the tone starts sounding like a curriculum, productivity system, or self-improvement plan, pull it back
## Contrast Policy
Contrast is allowed when all of the following are true:
- the emotional baseline has already been understood
- the contrast helps the user rather than entertaining the system
- the result still feels like OpenClaw chose the move on purpose
Good examples:
- a slightly brighter tone to keep the user from sinking too hard
- a harmless "venting game" to release irritation
- an unexpectedly sweet ending after a playful setup
Bad examples:
- jokes that outrun care
- heavy tenderness on a day that wants wit
- dramatic romance where the relationship frame does not support it
FILE:references/image-integration.md
# Image Integration
## Overview
Daily gift can optionally generate single-image gifts such as stickers, mood images, posters, proxy-character scenes, surreal stills, collages, or other image-first returns.
Use image output when the selected `gift_mode` or hybrid format decision points to `image`.
Current scope:
- setup and configuration are wired
- the runtime entry point exists
- image key detection and provider selection are wired
- provider-specific execution currently supports both `openrouter` and `gemini-direct`
- base64 image responses may be decoded and saved as local files when the provider does not return a plain URL
- all failures remain soft failures and should return `fallback_h5` instead of blocking the gift
## Runtime Entry Point
Use:
- `{baseDir}/scripts/render-image.sh <brief-json-file> <setup-state-file>`
The script is the runtime bridge for the image path.
At this stage it should:
- read image configuration from setup state
- detect the provider/runtime path based on setup configuration and available key sources rather than assuming one fixed provider
- dispatch internally to a provider path such as `gemini-direct` or `openrouter`
- validate the image brief shape
- call the actual provider API when a supported path is available
- decode base64 image payloads into local files when needed
- return structured JSON
- fall back cleanly to `h5` when provider execution fails or no usable credentials are available
Current internal runtime shape:
1. provider detection
2. provider-path dispatch
3. provider-specific execution
4. decode or normalize returned images
5. soft fallback when needed
## Prompt Hygiene
Image generation models treat ALL text in the prompt as potential visual content. Before sending any prompt to the image API:
- Remove all file names, paths, and technical references (e.g. `image_0.png`, `/tmp/output.jpg`, `base64`)
- Remove all internal variable names or API field names
- Remove all English technical instructions that are not part of the desired image content
- If referencing a user's image as input, do NOT mention the filename in the scene description — the API handles image attachment separately
- Double-check: would every word in this prompt make sense as something visible in the final image? If not, remove it.
This prevents the model from rendering debug text, filenames, or technical artifacts inside the generated image.
## Language Matching
When the user and OpenClaw communicate in Chinese, ALL text that appears inside the generated image must be Chinese — unless English is deliberately part of the concept (e.g. a fake English-language newspaper).
In the scene_description and text_overlay_spec, explicitly state: "All visible text in the image must be in Chinese (简体中文)."
The prompt itself may use English for scene/style instructions (image models often understand English prompts better), but any quoted text that should appear in the final image must be written in Chinese within the prompt.
Example:
- Bad: "Temperature display: 'Annoyed 23°'"
- Good: "Temperature display: '心烦 23°'"
## Post-Render Language Verification
After generation, verify the actual visible language before treating the image as complete.
This is mandatory whenever:
- the image includes any visible text
- the concept depends on Chinese wording being readable
- the borrowed-media shell or poster logic would break if the text language is wrong
Checks:
- is the visible text in the intended language
- are key words legible rather than garbled
- does the generated text match the concept closely enough to preserve the return
If the answer is no:
- retry once with stricter language instructions if the image format still makes sense
- reduce or simplify on-image text if the concept can survive with less
- switch to `h5` or direct `text` if exact wording is essential
Do not knowingly deliver an image whose visible language is wrong for the user or whose text corruption destroys the return.
## Brief File Contract
Pass a JSON file that contains at least:
- `user_input`
- `scene_description`
- `image_genre`
- `style_hint`
- `aspect_ratio_hint`
- `characters`: array of character descriptions appearing in the image, each carrying species, color, distinguishing features, and role in the scene; pull these from `workspace/daily-gift/user-portrait/` metadata plus any OC definitions in `SOUL.md`, `USER.md`, setup-state, or taste-profile when relevant
- `pov`: whose perspective the image represents, such as `openclaw watching user`, `user self-view`, or `third-person`; the composition should match this rather than drifting into a generic default angle
- `text_overlay_spec` when text should appear inside the image
When established character identities exist, include them explicitly in the prompt. Do not collapse them into generic `dog`, `fox`, `girl`, or `person` wording if the gift depends on recurring OC identity or a specific relationship viewpoint.
Recommended result contract:
```json
{
"render_mode": "image_urls",
"image_urls": ["https://.../gift.png"],
"tracking_url": "",
"provider": "openrouter",
"provider_path": "openrouter",
"model": "google/gemini-3.1-flash-image-preview",
"genre": "mood-photo",
"fallback_reason": "",
"warning": ""
}
```
`image_urls` may contain either:
- remote provider URLs
- local absolute file paths created by decoding returned base64 image data into `workspace/daily-gift/generated-images/`
Both are valid delivery artifacts. The caller should not assume the result is always an `https://` URL.
Possible `render_mode` values:
- `image_urls`
- `pending_tracking`
- `fallback_h5`
## Setup Requirements
Store these values in `workspace/daily-gift/setup-state.json` when image mode or hybrid mode is enabled:
- `gift_mode`
- `image.enabled`
- `image.provider`
- `image.model`
- `image.api_key_source` or `image.api_key`
### Default Image Model Strategy
If `image.model` is already configured in setup-state, use it.
The runtime should pass that configured model through as-is rather than hardcoding one exact accepted model name inside `render-image.sh`.
If no image model is configured, silently detect the best approved default from the available key path and persist it back to setup-state. Do not ask the user to choose from a comparison table during setup.
Current default policy:
- start with `google/gemini-3.1-flash-image-preview`
- detect supported image-generation keys in a fixed order and use the first one found
- if a direct Gemini or Google path is available through that detection order, prefer it over probing unrelated providers
- if a chosen model is rejected at generation time, fall back to the next approved option rather than stopping to ask the user about model routing
Persist the detected `provider`, `model`, and exact `api_key_source` so later runs stay stable instead of redetecting on every gift.
Provider may vary depending on where the user configured access to that model:
- direct Gemini or Google path using `GEMINI_API_KEY` or `GOOGLE_API_KEY`
- routed provider path such as `openrouter` using `OPENROUTER_API_KEY`
Prefer storing an environment variable source rather than a raw secret when possible.
If the user does not know which provider path to choose, OpenClaw should prefer the most direct working path it can detect from configured key sources rather than forcing the user to understand the routing details.
That means:
- use `gemini-direct` when a direct Gemini or Google key path is the clearest working route
- use `openrouter` when the user has configured access through `OPENROUTER_API_KEY`
- keep this decision inside the runtime bridge rather than asking the user to reason about implementation details unless setup is ambiguous
Recommended setup-state mapping when keys are auto-detected:
- `OPENROUTER_API_KEY` -> write `image.provider = openrouter` and `image.api_key_source = OPENROUTER_API_KEY`
- `GEMINI_API_KEY` -> write `image.provider = gemini-direct` and `image.api_key_source = GEMINI_API_KEY`
- `GOOGLE_API_KEY` -> write `image.provider = gemini-direct` and `image.api_key_source = GOOGLE_API_KEY`
Persist the detected `provider` and the exact detected `api_key_source`. Do not ask the user to choose between these routes when runtime context already makes the answer clear.
### API Key Detection Order
During setup or first image generation, silently check for these environment variables in order:
1. `OPENROUTER_API_KEY` -> use the OpenRouter path
2. `GEMINI_API_KEY` -> use the Gemini direct path
3. `GOOGLE_API_KEY` -> use the Google AI path
Use the first one found.
If none are found:
- note in setup-state that image generation is currently unavailable
- during onboarding setup, one casual non-technical ask is allowed before the first gift; see `{baseDir}/references/setup-flow.md`
- continue supporting `text` and `h5` gifts without image generation
Only the keys listed above are supported for image generation.
Do not probe for other API keys such as `OPENAI_API_KEY`.
Outside of the single onboarding ask described in setup flow, do not prompt the user for image API keys.
Exception:
- a rare, lightweight reminder is allowed in manual user-present runs when image capability is still missing and the current gift would be materially stronger as an image; see `{baseDir}/references/manual-run-flow.md`
- do not do this in cron-triggered runs
See also:
- `{baseDir}/setup-state.example.json`
## Provider Execution Notes
### `openrouter`
Use:
- `POST https://openrouter.ai/api/v1/chat/completions`
Recommended request shape:
- `model = google/gemini-3.1-flash-image-preview`
- `modalities = ["image", "text"]`
- one user message containing the final prompt
- include `image_config.aspect_ratio` when `aspect_ratio_hint` is present
Expected response shape:
- generated images usually appear in `choices[0].message.images[]`
- image data may be a remote URL
- image data may also be a base64 data URL such as `data:image/png;base64,...`
If the provider returns base64 data, decode it to a local file and return that local path in `image_urls`.
### `gemini-direct`
Use the Gemini image generation REST API directly, for example:
- `POST https://generativelanguage.googleapis.com/v1beta/models/gemini-3.1-flash-image-preview:generateContent`
Recommended request shape:
- authenticate with `x-goog-api-key`
- send `contents[].parts[].text` with the final prompt
Expected response shape:
- generated image bytes may appear in `candidates[].content.parts[].inline_data`
- `inline_data.mime_type` gives the mime type
- `inline_data.data` is base64-encoded binary image content
Decode each returned `inline_data` image to a local file and return those local paths in `image_urls`.
## Alternative: Direct Tool Invocation
If OpenClaw's runtime provides a built-in image generation tool, the agent may bypass `render-image.sh` entirely and:
1. call the image tool directly with the final prompt
2. receive an image path or URL from that tool
3. deliver it using the standard image delivery flow
This is preferred when available because it avoids shell-level API orchestration and benefits from OpenClaw's built-in auth, retries, and error handling.
`render-image.sh` remains the fallback runtime bridge for environments that prefer or require script-based execution.
## Genre Strategy
Image output uses genre cards rather than H5 pattern cards.
See:
- `./image-genre-chooser.md`
- `./image-genres/meme-sticker.md`
- `./image-genres/mood-photo.md`
- `./image-genres/proxy-character-scene.md`
- `./image-genres/borrowed-media-layout.md`
- `./image-genres/emotion-poster.md`
- `./image-genres/surreal-film.md`
These genres help choose:
- prompt framing
- subject treatment
- text-on-image tolerance
- whether the result should feel like a sticker, photo, poster, proxy-scene, or surreal still
- whether the user should appear directly, indirectly through a proxy character, or not at all
- whether the concept gains power by being framed inside a borrowed cultural medium such as a headline, cover, lyric screen, or certificate
- whether the image should stay mostly realistic while using light symbolic moves, which is often the sweet spot for `mood-photo`
- whether one emotional line should become the visual center of an original poster composition, which often points to `emotion-poster`
- whether the image needs analog grain, glow, and one strong impossible symbolic event, which often points to `surreal-film`
When a chosen genre file contains an `AI Generation Control` section, treat that section as the primary practical prompt-building guide for generation quality.
That means:
- do not stop at the genre's earlier `Prompt Strategy` section
- read the genre's `AI Generation Control` section before writing the final prompt
- use its magic words, poison words, composition rules, text rules, and prompt template as steering guidance rather than rigid formula
Direct self-image is no longer treated as a standalone image genre. If the gift has self-related material, use the chooser to decide whether that presence should become a proxy scene, poster, borrowed-media frame, mood-led still, or surreal symbolic figure.
Division of labor:
- this file defines universal image-quality and prompt-building principles that apply for all users
- `assets/examples/` and the image-genre reference assets define the concrete visual benchmark for what counts as good-looking in this skill; if the needed binary references are missing locally, fetch the relevant bundle first via `{baseDir}/scripts/fetch-asset-bundle.sh`
- `SOUL.md`, `MEMORY.md`, and live interaction context help infer the user's personal taste and how strongly to lean toward it
## When To Prefer Image
Prefer image when:
- one still frame can express the full anchor-plus-return pair
- interaction is unnecessary
- narrative sequencing is unnecessary
- the gift needs very polished visual finish or strong instruction following
- meme, atmosphere, collage, sticker, poster, proxy-character scene, or surreal still treatment is more fitting than panel-based structure
- OpenClaw wants the return to land through one precise frame rather than motion or participation
Do not default to image only because it seems easier. Choose it when the still-image form is itself the right return.
## Image As H5 Asset, Not Final Output
Sometimes image generation is not the gift itself.
Sometimes it is only one ingredient inside an H5.
When an H5 is being planned, use generated images only when they materially improve the concept:
- one real-looking background scene behind a wipe, reveal, or atmospheric interaction
- one poster-like environment that anchors the whole H5
- a small set of authored surfaces such as card faces, album pages, or parallel-world panels
Do not reach for image generation when pure code would already be stronger:
- generative particles
- kinetic text
- terminal or changelog aesthetics
- fake apps, dashboards, cards, or other CSS/SVG-first interfaces
- interaction-led concepts where motion, timing, and object behavior matter more than realism
The default for H5 should still be `assets: none (pure code h5)` unless generated images clearly add something code alone cannot achieve well.
If images are used as H5 assets, state what each one is for before rendering begins rather than generating them vaguely "for polish".
## Prompt Quality Rules
Image prompts should be concrete rather than generic.
Describe at least:
- the subject or scene
- the emotional treatment
- the visual style
- the framing or composition
- important objects, clothing, or environment details when relevant
Avoid prompts that only say "make it beautiful" or "in a nice style." The prompt should specify what kind of beauty or style is intended.
## Universal Aesthetic Principles
These apply to all image genres as a quality floor.
They are not personal style preferences.
### One strong visual idea per image
- a single unexpected composition choice beats stacking multiple beautiful elements
- before writing the prompt, state the one visual idea in one sentence
- everything else in the prompt should serve that one idea
### Describe observation, not inventory
- bad: `a park with cherry trees, a path, petals falling, sunlight, a bench`
- good: `cherry blossom petals trapped in the surface tension of a rain puddle, one petal just breaking through`
- the prompt should describe how we are seeing, not just what is there
### Material over label
- instead of `beautiful light`, describe the light's behavior, such as `low sun refracting through wet petals, casting pink caustics on the stone`
- instead of `dreamy atmosphere`, describe what creates it, such as `shallow depth of field with foreground bokeh from a rain-beaded window`
- specificity produces quality; labels alone usually produce generic images
### Less is usually more
- three well-chosen elements in a frame usually beat ten
- negative space, partial visibility, and what is deliberately left out of frame can be more powerful than what is shown
## Per-Genre Aesthetic Guide
Each genre has a different definition of `good`.
Use the matching guide when writing prompts.
### `mood-photo` / `surreal-film` — viewing method
What makes these genres high-quality is not the subject itself but the way the subject is observed.
Principles:
- prefer indirect observation: reflections, shadows, silhouettes, partial views, refractions, and surfaces
- `spring` can be water ripples distorting cherry blossoms, not just a person standing among flowers
- `rain` can be wet glass with bokeh city lights, not just someone holding an umbrella
- describe light behavior and material texture, not just scene elements
- when in doubt, remove the human figure; a scene that breathes on its own is often stronger than one anchored to a generic figure
- if a person must appear, prefer a back silhouette, a hand entering frame, a shadow, or a blurred form
- AI-generated full human figures often break the mood with uncanny details
Anti-patterns:
- `subject centered + pretty background + dramatic light` equals wallpaper, not art
- listing `6` or more beautiful things in one prompt
- including a person just because the frame feels empty without one
### `meme-sticker` — creative contradiction
What makes memes good is not visual beauty but unexpected emotional contradiction.
Principles:
- the humor comes from the gap between what is shown and what it means
- exaggerate one thing: the emotion, the prop, the scale, or the context, but not everything at once
- keep it readable at thumbnail size; busy memes die fast
- cheap, lo-fi, slightly cursed aesthetics are often funnier than polished renders
- deadpan delivery is often funnier than a character mugging at the camera
Anti-patterns:
- generic cute character plus text caption
- trying to be beautiful and funny at the same time instead of choosing a priority
- overexplaining the joke in the prompt
### `emotion-poster` — typography as emotion
What makes posters good is the fusion of typography and image, not either one alone.
Principles:
- the text is the design, not something pasted on top
- specify exact typographic feeling: size, weight, placement, language, and serif, sans, or handwritten direction
- the image should feel like it was made for this text, not the other way around
- sparse is usually stronger than busy; one line with breathing room often hits harder than a paragraph
- think album cover, film poster, or poetry broadside, not presentation slide
Anti-patterns:
- a beautiful image with floating text unrelated to the composition
- too much text
- commercial or ad-like energy instead of emotional or literary energy
### `borrowed-media-layout` — convincing disguise
What makes this genre work is how convincingly it imitates a real medium.
Principles:
- the borrowed medium should be immediately recognizable: newspaper, karaoke screen, book cover, certificate, album sleeve, movie ticket, and so on
- get the details right: date formats, column layouts, publisher marks, barcodes, issue numbers, age ratings
- the content inside can then be personal, absurd, or touching, creating contrast with the serious shell
- the more real the shell looks, the funnier or more touching the content becomes
Anti-patterns:
- a vaguely newspaper-ish or certificate-ish layout that does not feel like any real medium
- missing metadata details that sell the illusion
- content too generic to justify the borrowed frame
### `proxy-character-scene` — distance creates intimacy
What makes this genre work is the tension between an artificial proxy and a real environment.
Principles:
- the proxy, such as a doll, plush, toy, or figure, should look deliberately artificial
- the environment should feel real, textured, and lit like a photograph
- that contrast, fake being in a real place, creates the emotional register
- the proxy is a stand-in for the user, so its pose, placement, and scale should suggest an emotional state
- lighting and environment do most of the emotional work; the proxy mainly needs to be there
Anti-patterns:
- making the proxy too realistic
- making the environment too artificial
- centering the proxy without giving the environment enough presence
## Text Inside Images
Image generation may include text, but only when it materially improves the gift.
If text is included, specify:
- the exact wording
- the language, which should match the user's dominant interaction language with OpenClaw
- the placement
- the approximate size
- the font feel or typographic direction
Text must feel naturally integrated with the image content rather than pasted on top.
Avoid layouts that are likely to produce broken text structure, especially for Chinese.
Keep on-image text as short as possible. Long paragraphs or dense Chinese copy are high risk and should usually be avoided in favor of a shorter line plus stronger visual composition.
When in doubt, prefer less text and stronger image composition over a text-heavy frame.
## Aspect Ratio
Default to a mobile-friendly `9:16` aspect ratio for image gifts unless another ratio clearly serves the composition better.
Use a different ratio only when the return depends on it, such as a poster-like vertical crop versus a wide cinematic frame.
Genre-specific override:
- `meme-sticker` often works better in `1:1` or `3:4` because the joke needs to read quickly and the subject is usually a compact reaction image rather than a tall scene
## High-Level Rules
- Treat image output as an alternate rendering path, not as a replacement for synthesis or editorial judgment.
- Keep the same anchor-plus-return standard as other formats.
- Prefer image when one frame can carry the full gift.
- Keep the runtime bridge provider-agnostic even though the current dispatched paths are `gemini-direct` and `openrouter`.
- If the runtime cannot finish image generation, return `fallback_h5` rather than blocking the gift.
FILE:references/visual-strategy-contract.json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "VisualStrategy",
"type": "object",
"required": [
"creative_concept",
"selected_format",
"concept_format_rationale",
"output_shape",
"render_path",
"screen_count",
"interaction_grammar",
"asset_strategy"
],
"properties": {
"creative_concept": {
"type": "string",
"description": "The chosen one-sentence creative concept from Stage 2.5 that this visual strategy is implementing."
},
"selected_format": {
"type": "string",
"enum": ["h5", "image", "video", "text", "text-play"]
},
"concept_format_rationale": {
"type": "string",
"description": "Why this selected format serves the chosen concept better than the nearest alternative."
},
"pattern_id": {
"type": "string",
"description": "H5 pattern identifier when the selected format is h5."
},
"output_shape": {
"type": "string",
"description": "Chosen output-shape category for repetition control and form planning. Prefer the recommended taxonomy in delivery-policy.md when possible, but use a new stable high-level label when a genuinely new form does not fit existing categories."
},
"visual_style": {
"type": "string",
"description": "Chosen high-level visual-style label for repetition control, such as dark-terminal, dark-cinematic, light-warm, colorful-playful, minimal-poster, pixel-retro, photographic, or a stable custom label."
},
"render_path": {
"type": "string",
"enum": ["code-first", "image-first", "hybrid", "chat-native"]
},
"screen_count": {
"type": "integer",
"minimum": 1
},
"interaction_grammar": {
"type": "string"
},
"asset_strategy": {
"type": "string",
"description": "One-line asset plan decided before rendering begins, such as `assets: none (pure code h5)`, `assets: 1 background image (airport rain scene)`, or `assets: 1 reference frame for video`."
},
"repetition_note": {
"type": "string",
"description": "Brief note on whether this output shape, visual style, and content direction are fresh enough relative to recent gifts, or why deliberate repetition is acceptable."
},
"image_genre": {
"type": "string",
"description": "Image genre when the selected format is image."
},
"video_genre": {
"type": "string",
"description": "Video genre when the selected format is video."
},
"video_mode": {
"type": "string",
"description": "Chosen video payload mode when the selected format is video. Record whether this piece should be `text-to-video`, `first-frame`, or `first-last-frame`."
},
"video_model": {
"type": "string",
"description": "Optional explicit video model override when the runtime should not use its normal mode-based default."
},
"text_play_type": {
"type": "string",
"description": "Bounded text-play subtype when the selected format is text-play."
},
"turn_limit": {
"type": "integer",
"minimum": 1,
"description": "Planned maximum number of turns for bounded text-play."
},
"generate_audio": {
"type": "boolean",
"description": "Whether the selected video plan should request generated audio."
},
"style_notes": {
"type": "array",
"items": {
"type": "string"
}
}
},
"examples": [
{
"creative_concept": "A tiny bedside radio that tunes into tonight's mood and reveals one connected lyric message as the user switches stations.",
"selected_format": "h5",
"concept_format_rationale": "The concept works best as an object the user actively tunes, so interaction carries the return better than a static text artifact or passive video clip.",
"output_shape": "object-reveal",
"visual_style": "dark-cinematic",
"render_path": "code-first",
"screen_count": 1,
"interaction_grammar": "tap stations, dial rotation, lyric reveal",
"asset_strategy": "assets: none (pure code h5)",
"repetition_note": "Output shape is fresh enough, and although the palette is dark, the recent gifts were not dark-heavy enough to trigger a forced shift.",
"style_notes": [
"Use warm amber highlights instead of terminal green.",
"Keep typography cinematic rather than code-like.",
"Treat the radio as the center object with tactile depth."
]
}
],
"additionalProperties": true
}
FILE:references/gift-format-chooser.md
# Gift Format Chooser
Use this file as the top-level quick chooser before diving into any format-specific index.
Use it after the creative concept is already clear. If the concept still sounds bland, go back before choosing the medium.
A strong format cannot rescue a weak idea.
This file answers:
- should the gift become `h5`, `image`, `video`, `text`, or `text-play`
- which format-family seems most likely to carry the thesis
- which format-specific quick index to read next
After choosing the format, continue into the matching local index:
- `h5` -> `pattern-boundaries.md`
- `image` -> `image-genre-chooser.md`
- `video` -> `video-genre-chooser.md`
- `text` -> `delivery-rules.md`
- `text-play` -> `manual-run-flow.md` and `delivery-rules.md`
## Quick Map
Choose `h5` when:
- interaction is the meaning, not just decoration
- the gift should feel like an object, device, scene, ritual, or container the user can touch
- text, reveal, drag, wipe, bloom, countdown, or tactile objecthood carries the return
- the user's own words should remain visible and alive inside the artifact
Choose `image` when:
- one polished still frame can carry the whole return
- atmosphere, poster logic, symbolic stillness, or borrowed-media grammar is central
- the gift does not need time to unfold
- the emotional point should land through a single art-directed image
Choose `video` when:
- motion, timing, loop behavior, or transition is the return
- the viewer should watch the feeling unfold rather than trigger it directly
- a short clip can express atmosphere, drift, transformation, or real-scene magic better than a still
- cinematic polish matters more than user participation
- the gift does not rely on lots of clearly readable on-screen text
Choose `text` when:
- the core value is in the writing itself
- the gift should read like a letter, observation diary, note, analysis, recommendation, or narrative
- exact wording matters more than visual treatment
- adding an image would be supplementary rather than essential
Choose `text-play` when:
- the interaction itself is the gift rather than a wrapper around the gift
- the user is present and likely willing to reply with very small inputs
- delight comes from live unfolding, guessing, branching, co-writing, or role-play
- the concept can stay bounded and resolve naturally within `5-10` turns
- chat-native immediacy is better than building a page or polished static artifact
## Fast Boundary Notes
`h5` vs `video`:
- choose `h5` when touch, drag, wipe, or reveal should respond to the user
- choose `video` when timing, loop rhythm, camera feeling, or watch-first polish matters more
- choose `h5` when the point depends on exact wording being clearly readable
- choose `image` instead of `video` when one strong frame is enough and the clip would mainly exist to carry text
`image` vs `text`:
- choose `image` when the picture itself carries the return
- choose `text` when the written content is the actual gift and the visual can only frame it lightly
`text` vs `h5`:
- choose `text` when the writing can land directly without interaction
- choose `h5` when the writing needs controlled reveal, tactile pacing, browseable structure, or exact visual staging
`text` vs `text-play`:
- choose `text` when the writing should arrive complete in one finished artifact
- choose `text-play` when the return depends on live progression and small user responses
`text-play` vs `h5`:
- choose `text-play` when the interaction should stay chat-native, frictionless, and conversational
- choose `h5` when the interaction should happen inside an authored object, page, mini-game, or scene
## Text-Play Tone Rule
When the selected format is `text-play`, optimize for play first and insight second.
Default tone:
- light
- curious
- game-like
- inviting enough that the user wants to answer immediately
Prefer:
- playful framing over therapeutic framing
- imagination over direct confrontation
- absurd, fictional, or game-shaped prompts over realistic self-analysis
- `pick one`, `name it`, `guess`, or `what happens` over explanatory questions
- humor and surprise over earnest processing
- casual, textured chat language over polished prose
The real point should land later as a surprise return, not as the opening thesis.
If the concept only works when its insight is explained upfront, it is probably a better fit for `text` or `h5` than `text-play`.
## Text Precision Rule
Use the format that matches how image and video models actually behave, not how we wish they behaved.
Reliable enough:
- one very short line
- one decorative label
- one obvious title where minor typography drift would not destroy the gift
Not reliable enough to trust image or video generation:
- exact dates
- exact names
- exact numbers
- multiple distinct text blocks
- table rows, report fields, or form-like structures
- medium or long Chinese sentences
- any gift where a wrong word would weaken or change the return
Therefore:
- if exact wording is the gift, choose `text`
- if exact wording must live inside a visual artifact, choose `h5`
- do not choose `image` or `video` just because they are faster when the concept is text-precision-critical
- treat image and video text as fragile decoration unless the amount of text is extremely small
## Variety Reminder
Before locking the format, review the last `5` gifts in `recent_gifts`.
- if `3` or more of the last `5` were `h5`, actively consider `image`, `video`, or `text` this time
- if `3` or more of the last `5` were `image`, actively consider `h5`, `video`, or `text` this time
- if `3` or more of the last `5` were `video`, actively consider `h5`, `image`, or `text` this time
- if `3` or more of the last `5` were `text`, actively consider `h5`, `image`, or `video` this time
- if `3` or more of the last `5` were `text-play`, actively consider `h5`, `image`, `video`, or `text` this time
This is not a hard rule. If the concept genuinely demands one format, use it. But when multiple formats could work, prefer the underrepresented one.
## Expression Map
- tactile reveal, browseable keepsake, mini-game, or poetic interaction -> start with `h5`
- one polished poster, mood frame, surreal still, or borrowed-media shell -> start with `image`
- loop, drift, transformation, animated atmosphere, or real-scene magic -> start with `video`
- letter, diary, recommendation, reflection, analysis, or story where the wording is the gift -> start with `text`
- live co-creation, emoji riddles, micro-adventures, collaborative story beats, or tiny role-play -> start with `text-play`
## Reminder
Do not choose by trend word alone. Choose by what carries the return, whether time matters, whether interaction should happen live in chat or inside an artifact, whether one frame is enough, and whether exact writing is the main emotional payload.
FILE:references/h5-mobile-patterns.md
# H5 Mobile Patterns
Adapted from frontend-design-ultimate for single-page H5 gifts viewed on mobile phones.
## Why This Matters
Daily gift H5s are viewed almost exclusively on mobile phones such as Telegram or WeChat in-app browsers. Every design decision must be mobile-first.
## Viewport Setup
Always include:
```html
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
```
## Font Size Rules
- Minimum body text: `13px`
- Main display text: use `clamp()` or `vw` units to scale with screen width
- iOS zooms on input focus if `font-size < 16px`; avoid form elements below that
- Test readability at `375px` width, the narrowest common screen
## Touch Target Sizes
- Minimum `44x44px` for any tappable element
- Audio toggle button: at least `36x36px` with adequate padding
- If the gift has tap interactions, make tap zones generous
## Safe Areas
- Top `44px`: may be covered by the phone status bar or in-app browser header
- Bottom `34px`: may be covered by the iPhone home indicator
- Keep critical content away from edges; use padding of at least `16px` on all sides
## Canvas Sizing
For `p5.js` gifts:
```javascript
function setup() {
createCanvas(windowWidth, windowHeight);
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
```
Always handle `windowResized()`. Phones rotate, and in-app browsers may resize mid-session.
## Text on Canvas
When using `p5.js text()`:
- `textSize` should be relative to canvas width, not hardcoded pixels
- Example: `textSize(width * 0.04)` instead of `textSize(16)`
- This keeps text proportional across screen sizes
- Test on both narrow (`375px`) and wide (`428px`) phone screens
## Aspect Ratio Considerations
Most gift H5s work best at full-screen mobile, approximately `9:16` to `9:19.5`:
- do not design for desktop-width layouts
- do not assume landscape orientation
- vertical scrolling is acceptable, but auto-play gifts should fit one screen
## Performance
Mobile phones have limited GPU and CPU:
- keep particle count under `100` for smooth animation unless there is a strong reason otherwise
- avoid heavy blur filters on large areas
- base64-encoded audio should be under `500KB`
- total HTML file size should stay under `1MB` for fast loading
- test mentally for mid-range phones, not just flagship devices
## Color and Contrast
- phone screens vary widely in brightness and color accuracy
- avoid very low contrast text
- dark mode gifts often look richer on OLED screens
- consider both bright daylight and dark-room viewing
## Common Mobile Failures
| Failure | Fix |
|---|---|
| Text too small to read | Use relative sizing such as `vw` or width-based sizing |
| Tap targets too small | Keep minimum `44x44px` |
| Content behind status bar | Add top padding |
| Canvas does not resize on rotate | Implement `windowResized()` |
| Animation janky on older phones | Reduce particle count |
| Audio does not play | Add a `touchstart` listener for the first interaction |
| File too large, slow to load | Compress audio and limit total size |
FILE:references/asset-manifest.json
{
"image-examples/borrowed-media-layout": "https://dayfold-opensource.oss-cn-shanghai.aliyuncs.com/gift-everyday/img-borrowed-media-layout.zip",
"image-examples/emotion-poster": "https://dayfold-opensource.oss-cn-shanghai.aliyuncs.com/gift-everyday/img-emotion-poster.zip",
"image-examples/meme-sticker": "https://dayfold-opensource.oss-cn-shanghai.aliyuncs.com/gift-everyday/img-meme-sticker.zip",
"image-examples/mood-photo": "https://dayfold-opensource.oss-cn-shanghai.aliyuncs.com/gift-everyday/img-mood-photo.zip",
"image-examples/proxy-character-scene": "https://dayfold-opensource.oss-cn-shanghai.aliyuncs.com/gift-everyday/img-proxy-character-scene.zip",
"image-examples/surreal-film": "https://dayfold-opensource.oss-cn-shanghai.aliyuncs.com/gift-everyday/img-surreal-film.zip",
"video-examples/live-scene-doodle": "https://dayfold-opensource.oss-cn-shanghai.aliyuncs.com/gift-everyday/vid-live-scene-doodle.zip",
"video-examples/relatable-surrealism": "https://dayfold-opensource.oss-cn-shanghai.aliyuncs.com/gift-everyday/vid-relatable-surrealism.zip",
"examples/extension": "https://dayfold-opensource.oss-cn-shanghai.aliyuncs.com/gift-everyday/h5-extension.zip",
"examples/gifted-data-viz": "https://dayfold-opensource.oss-cn-shanghai.aliyuncs.com/gift-everyday/h5-gifted-data-viz.zip",
"examples/inner-mirror": "https://dayfold-opensource.oss-cn-shanghai.aliyuncs.com/gift-everyday/h5-inner-mirror.zip",
"examples/kinetic-collage": "https://dayfold-opensource.oss-cn-shanghai.aliyuncs.com/gift-everyday/h5-kinetic-collage.zip",
"examples/light-gamification": "https://dayfold-opensource.oss-cn-shanghai.aliyuncs.com/gift-everyday/h5-light-gamification.zip",
"examples/memory-shelf": "https://dayfold-opensource.oss-cn-shanghai.aliyuncs.com/gift-everyday/h5-memory-shelf.zip",
"examples/wind-scatter": "https://dayfold-opensource.oss-cn-shanghai.aliyuncs.com/gift-everyday/h5-wind-scatter.zip",
"audio": "https://dayfold-opensource.oss-cn-shanghai.aliyuncs.com/gift-everyday/audio-presets.zip"
}
FILE:references/h5-design-philosophy.md
# H5 Design Philosophy
Adapted from frontend-design-ultimate for single-page H5 gift contexts using `p5.js`, canvas, and CSS.
## The Problem: AI-Slop H5 Gifts
Generic AI-generated H5 gifts often share these signs:
### Typography Sins
- only one font weight used throughout
- text all the same size, with no hierarchy
- centered everything with no rhythm
- generic system fonts with no personality
### Color Crimes
- pure black background with white text as lazy dark mode
- no color hierarchy
- random accent colors that do not connect to the gift's mood
- no warmth or temperature in the palette
### Layout Laziness
- everything dead-center on screen
- perfectly symmetrical with no tension
- elements stacked vertically with uniform spacing
- no visual surprise or asymmetry
### Motion Mediocrity
- CSS fade-in on everything with the same timing
- no orchestration
- no easing variety
- no relationship between motion and meaning
### Background Boredom
- solid black or solid dark blue
- plain CSS gradient
- no texture, grain, or depth
## The Solution: Intentional H5 Design
### Color As Emotion
Build the palette from the gift's emotional register:
- dark + confident: deep blacks, muted accents, one bright signal color
- warm + healing: cream, amber, sage, soft pink
- poetic + melancholy: desaturated blues, muted purples, rain-grey
- playful + bright: saturated primaries, white space, clean contrast
Use the `60-30-10` rule: `60%` dominant background, `30%` secondary elements, `10%` accent highlights.
### Typography As Voice
Even when text is rendered on canvas, keep hierarchy:
- one main text: larger and more visible
- supporting text: smaller and lighter
- accent text such as date stamps or labels: tiny and subdued
- use `textSize()` deliberately, not uniformly
- letter spacing matters; loose feels calm, tight feels urgent
### Motion As Narrative
Animation should tell a story rather than merely move:
- stagger entry timing
- match easing to mood
- use delay to create beats
- connect particles to emotional meaning
### Background As Atmosphere
The background is the first thing the viewer feels:
- generated image backgrounds often add richness CSS gradients cannot
- subtle noise or grain removes sterile digital feel
- vignette helps focus attention
- bokeh or soft light circles add depth
## Design Decision Quick Test
Before shipping an H5 gift, ask:
1. Would I screenshot this?
2. Does it feel designed or generated?
3. What is the one element that makes this gift unique?
4. Is the motion orchestrated or random?
5. Does the background have atmosphere or is it just a color?
## Anti-Pattern Detection
| Anti-Pattern | Fix |
|---|---|
| All text same size | Apply clear size hierarchy |
| All text centered with same spacing | Vary position, alignment, and spacing |
| Pure CSS gradient background | Add texture, grain, or generated image |
| Everything fades in at once | Stagger with meaningful delays |
| No color temperature | Choose warm or cool and commit |
| Particles without purpose | Connect particle type to mood |
| Generic system font | Use a more intentional font choice, including a CDN-loaded web font when appropriate |
FILE:references/html-spec.md
# H5 Gift HTML Spec
This file defines the output contract for generated H5 gifts.
The goal is smooth delivery across OpenClaw contexts:
- best case when hosted preview is configured: send a hosted URL that opens directly in-channel, such as a Telegram Web App button
- strong local fallback: immediate Canvas presentation
- universal fallback: send a single HTML file through a file-capable channel
## Core Output Rule
Every final H5 gift should be generated as a single HTML file.
That means:
- one `.html` file
- no required external asset folder
- no dependency on a local dev server
- no dependency on private infrastructure
It does **not** mean every byte must be inlined.
For final gifts, use this external-resource policy:
- JavaScript libraries: CDN allowed
- Fonts: CDN allowed
- Images and custom visual assets: must be inline
## External Resource Policy
### JavaScript Libraries
CDN use is allowed for stable public libraries such as:
- p5.js
- Three.js
- GSAP
Rules:
- pin exact versions, never use `@latest`
- prefer stable public CDNs such as `jsdelivr`, `cdnjs`, or `unpkg`
- add integrity hashes when practical
- only include libraries the gift actually needs
### Fonts
CDN-hosted fonts are allowed.
Good sources:
- Google Fonts
- stable public font CDNs
Rules:
- prefer a small number of font requests
- do not depend on obscure or fragile font hosts
### Images And Custom Assets
These must be embedded inline.
Use:
- base64 `data:` URIs
- inline SVG where appropriate
Rich H5 gifts may use multiple composited sprites or transparent PNG layers, but those custom assets must still be embedded inline in the final HTML.
Do not rely on:
- external image URLs
- temporary object storage links
- third-party image hosts
## Required
- single-file HTML output
- all essential images embedded inline, ideally as `data:` URIs
- include `<meta name="viewport" content="width=device-width, initial-scale=1.0">`
- work as a standalone file when opened directly
- keep the result mobile-friendly even if Canvas is later used for desktop display
- if using CDN libraries or fonts, lock versions and use stable public sources
- provide a lightweight loading state when CDN resources may take a moment to resolve
- before delivery, open the generated HTML in a browser testing environment using `profile="openclaw"` and verify that the page renders, the core interaction works, important content is reachable, bottom-fixed UI remains accessible, and text is readable
- if browser self-test cannot complete even with `profile="openclaw"`, do one manual source review for obvious layout or interaction problems and include an explicit warning in delivery that browser self-test was skipped
## Strongly Recommended
- keep the final file reasonably small, ideally under `200KB` before CDN-loaded libraries and fonts
- prefer CSS animation over heavy JavaScript animation when the effect allows it
- keep the number of moving parts low
- include one clear focal point on first render
- make the first interaction immediately understandable
- when a gift can be done well without CDN libraries, prefer the simpler path
## Visual Quality Floor
The templates under `{baseDir}/assets/templates/` represent the minimum visual quality bar, not the ceiling.
That means the final gift should usually show:
- deliberate composition rather than default centered blocks
- typography chosen for the mood, not whatever default font loads first
- text containers, borders, textures, shadows, or surfaces that help the words feel placed rather than pasted
- enough atmosphere to feel complete when the concept calls for it, such as star fields, light particles, rain, glow, grain, depth layers, or other scene-setting details
- motion that feels intentional and tuned, not abrupt or obviously placeholder
Use richer visual tools when they materially improve the craft:
- `three.js`
- `p5.js`
- `GSAP`
- other stable visual libraries with pinned versions
Do not add libraries for decoration alone. Use them when they help the gift reach a level of polish, immersion, or object-feeling that simpler code would miss.
The gift should not feel:
- rushed
- flat
- like a quick demo
- like generic component layout with emotional copy dropped into it
- obviously less polished than the nearest relevant template
Whenever the user's prior interaction suggests a clear visual preference, bias the palette, typography, density, and atmosphere toward that preference.
## Motion And Physical Feeling
When the gift concept implies a physical object such as a box, drawer, card, envelope, cabinet, shelf, or folded note:
- the object should visibly open, close, pull, slide, flip, lift, or otherwise behave like the thing it claims to be
- transitions should use spring-like easing rather than flat linear motion
- elements should feel like they have weight, friction, resistance, or momentum
- prefer CSS spring-style motion, tuned keyframes, or `GSAP` for object motion over simple opacity fades
A box that does not open is not a box.
A drawer that does not pull is not a drawer.
If the metaphor implies physics, deliver physics.
## Delivery Strategy
Preferred display order:
1. Generate the final single HTML file.
2. Save it under the gifts output folder.
3. Run the mandatory browser-based functional self-test on that HTML file using `profile="openclaw"`.
4. If browser self-test cannot complete, do one manual HTML review for obvious issues and prepare an explicit delivery warning that browser self-test was skipped.
5. Run `{baseDir}/scripts/deliver-gift.sh <html-file> workspace/daily-gift/setup-state.json` to resolve the delivery path from setup state.
6. If the script returns `delivery_mode = hosted_url`, send that URL first.
7. When the active channel supports it, wrap the hosted URL in the lightest open affordance available, such as a Telegram Web App button or equivalent in-app web container.
8. If the script returns `delivery_mode = local_file` and OpenClaw Canvas is available and enabled, present the file there for the smoothest local interactive experience.
9. If the script returns `delivery_mode = local_file` and Canvas is unavailable, send the HTML file itself when the channel supports file delivery.
Do not assume Canvas exists in every runtime context, and do not assume public hosting is always configured.
## Optional Hosting Guidance
Hosted preview should improve delivery friction, not become a hard dependency.
Recommended default:
- `surge`
Why `surge` is the simplest default:
- email-based setup
- no credit card requirement
- one-time login with locally stored credentials
- one-command deploy flow that works well for single-page gifts
Suggested deployment shape:
- copy the generated HTML into a temporary directory as `index.html`
- deploy that directory
- return the resulting HTTPS URL
Implementation note:
- keep the skill's runtime contract provider-agnostic even if `surge` is the default recommendation
- use `scripts/deliver-gift.sh` as the runtime entry point that reads setup-state hosting config before calling `scripts/deploy.sh`
- if deployment fails, fall back to Canvas or direct HTML file delivery
## Output Path Convention
Recommended output location:
- `workspace/gifts/YYYY-MM-DD-<slug>.html`
If multiple gifts are generated in one day, append a short suffix.
## Cleanup Strategy
- keep generated HTML gift files for the most recent `30` days by default
- older HTML files may be deleted to keep the workspace light
- deleting old HTML files should not delete gift-history records or other metadata
## Forbidden
- no external image URLs for critical rendering
- no `@latest` for CDN libraries
- no unauthenticated runtime dependency on private or fragile resources
- no required resources that need login or API auth just to render the gift
- no required API calls or fetches during page load
- no localStorage requirement for normal viewing
- no assumption that a separate server is running
## Important Nuance
Authoring templates may use development-time helpers or external references while being designed.
The final delivered gift should still be robust as a single HTML artifact:
- CDN libraries and fonts are acceptable when pinned and stable
- images and custom assets must still be embedded inline
FILE:references/evaluation-rubric.md
# Evaluation Rubric
This file defines how to judge whether a generated gift is actually good.
The standard is not "did the system output something." The standard is whether the output deserved to exist and whether it turned context into a relationship-aware return.
## Core Principle
A good gift is not:
- raw recording
- plain summary
- generic encouragement
- random visual novelty
A good gift is:
- selected
- interpreted
- emotionally and relationally situated
- returned with angle, care, and form
In other words:
- `memory.md` is closer to archive
- a summary is closer to repetition
- a gift is explanation plus return
- an editorial gift is chosen, shaped, and relationally given back
## Fail-Fast Checks
If any of these fail badly, the gift should usually be considered a miss even if some other parts are decent.
### 1. Necessity
Ask:
- Was there enough emotional value, informational value, or relational value to justify a gift at all
- Would skipping have been better than sending this
Fail examples:
- the gift adds almost nothing to the day
- the system appears to have sent it only because it could
### 2. Relational Specificity
Ask:
- Is this clearly about this user and this OpenClaw relationship
- Could this artifact have been sent to almost anyone with only minor edits
Fail examples:
- broad praise
- abstract comfort with no concrete tie to the day
- output that feels detached from the actual relationship
### Visible Connection
Ask:
- If the user received this gift after today's conversation, would they feel heard or ignored
Fail:
- the gift has zero detectable thread to anything the user said, felt, or experienced today
### Interaction Cost Fit
Ask:
- Does this gift's required effort match the user's likely energy level today
Fail:
- the gift demands typing or creative input on a day when the user was clearly stressed, sad, or exhausted
### 3. Basic Completion
Ask:
- Does the artifact function
- Is it readable, aligned, and visually coherent
- If interactive, is the interaction obvious enough to use without effort
- Was the artifact actually opened and checked in a browser-like environment before delivery
- If browser self-test could not complete, was that failure handled explicitly rather than silently ignored
Fail examples:
- visible overlap, broken layout, missing assets, or obvious errors
- interaction that requires instruction to decode
- content that looks acceptable in code but fails when actually opened and used
- browser self-test failed or never connected, but the gift was still delivered as if it had passed
### 4. Thesis Focus
Ask:
- Is the gift clearly about one main thing, or at most two tightly related things
- Do the supporting details stay in supporting roles instead of competing for equal attention
- Does the artifact feel selected rather than like a decorated memory dump
Fail examples:
- six valid context fragments all appear to have equal narrative weight
- the gift behaves like a beautifully styled recap instead of a shaped return
- every extracted slot is visible because it was available, not because it earned the space
### 5. Thesis Clarity
Ask:
- Can I state this gift's thesis in one sentence that also suggests a specific interactive or visual form
- Does the thesis point toward one strong angle rather than several loosely related observations
- Does that thesis include both the anchor and the return, rather than only naming the event
Fail examples:
- "this gift shows several things about the day" without a single clear angle
- the thesis sentence stays abstract and does not imply what the artifact should actually do or feel like
- the thesis names the event but does not say what new thing is being returned to the user
### 6. Concept Novelty
Ask:
- Would the user say `哇这个有意思` or just `嗯还挺好看的`
- Does the concept have its own rules, or is it just content with decoration
- Could someone describe it as a thing or invention, rather than an effect or layout
- Is the concept structurally different from the last `3` gifts
Fail examples:
- the concept is a standard format application with no independent logic
- the concept could be described as `nice [format] with [content]` without any unique structural twist
- the concept does not pass the `would you show it to a friend because the concept itself is interesting` test
### 7. Form Novelty
Ask:
- Have I used this exact output shape in the last three gifts
- Am I defaulting again to familiar surfaces such as card grids, sticky-note boards, or fragment collections without a real reason
Fail examples:
- three consecutive gifts that are all themed cards on a surface
- the color palette changes but the underlying output shape is effectively identical
### 8. Visual Craft Floor
Ask:
- Does the artifact look intentionally designed rather than quickly assembled
- Is the visual finish at least on par with the relevant templates
- Do typography, spacing, surfaces, and atmosphere feel considered
Fail examples:
- default-looking typography with no visible taste or mood choice
- large blank areas or weak composition that make the gift feel unfinished
- text, images, and motion that technically work but look obviously rushed or generic
- output that is materially less polished than the nearest relevant template
## Primary Scoring Axes
Score each axis from `1` to `5`.
- `1`: poor / clearly failed
- `2`: weak / partially present
- `3`: acceptable / usable but unremarkable
- `4`: strong / clearly successful
- `5`: excellent / memorable and highly fitting
## 1. Editorial Necessity
Does this gift deserve to exist today
High score:
- the gift is clearly justified by today's context
- sending it feels more right than skipping it
- it creates meaningful emotional, informational, or relational value
Low score:
- the output feels forced
- the day did not need a gift
- the artifact adds little beyond noise
## 2. Editorial Return Quality
Can the gift transform all of the following into a relationship-aware return:
- what happened today
- what the user actually cared about
- how it connects to the user's past
- why it deserves to be remembered
High score:
- the output does not merely repeat the day
- it selects and interprets
- it gives back an angle or frame
- the gift returns something the user did not already fully have
Low score:
- it behaves like a transcript recap
- it spreads attention across too many equal fragments
- it replays the anchor without adding a real return
- it records without shaping
## 3. Information Gain
Does the gift add something the user did not already fully have
High score:
- offers a clear new angle, pattern, or compression
- helps the user see the day differently
Low score:
- simply tells the user what already happened
- offers no reason to revisit the artifact
## 4. Decision Gain
After seeing the gift, is anything clearer for tomorrow
High score:
- the user gains clarity, direction, steadiness, or perspective
- even a small practical or emotional next-step becomes easier
Low score:
- the artifact is pure echo
- nothing becomes clearer or more actionable
## 5. Relationship Gain
Does the artifact deepen the relationship between OpenClaw and the user
High score:
- feels like "someone understood me and gave something back"
- increases trust, intimacy, companionship, or being-seen feeling
Low score:
- feels like a system log, automated recap, or detached demo
## 6. Narrative Tension
Does the gift create shape rather than flatten life into flatness
High score:
- selects a strong angle
- introduces compression, contrast, reveal, or framing
- makes even an ordinary day newly legible or alive
Low score:
- life was already flat and the artifact makes it flatter
- the output is faithful but dull
## 7. Surprise Quality
Surprise should come from cognition, not random form switching.
Evaluate whether surprise comes from:
- an unexpected but precise angle
- one very accurate line of explanation
- a fitting extension, reference, or reframe
High score:
- the surprise feels like recognition plus shift
Low score:
- the surprise is only aesthetic or gimmicky
- the form changes but the understanding does not
## 8. Personalization Density
How unmistakably is this gift about this user
High score:
- details feel highly specific
- quotes, references, memory echoes, and preferences are well chosen
- the user could tell this was made for them
Low score:
- the gift remains broad or generic
- user-specific detail is missing or cosmetic
## 9. Emotional Fit
Does the emotional register match the event and the user's broader mood that day
High score:
- the gift shows strong social and emotional intelligence
- warmth, humor, tenderness, critique, or play are all correctly calibrated
Low score:
- the tone is mismatched
- the gift is too harsh, too cheerful, too heavy, too flippant, or too cold
## 10. Form-Content Alignment
Does the chosen form actually match the content
High score:
- the visual and interaction logic reinforce the core meaning
- form and content feel designed together
Low score:
- content and form feel disconnected
- a flashy format is carrying unrelated material
## 11. Taste And Finish
Does the gift feel aesthetically complete and intentional
High score:
- layout is clean
- elements align
- typography is readable
- the artifact looks like a finished object
Low score:
- obvious spacing, overlap, styling, or alignment problems
- visual taste feels generic or sloppy
## 12. Interaction Clarity
If the gift has interaction, is it immediately understandable
High score:
- the user can tell what to do without friction
- one core action is easy to discover
Low score:
- unclear interaction affordances
- too much learning cost for too small a payoff
## 13. Scope Discipline
Is the gift's complexity appropriate to the weight of the event
High score:
- small event, light form
- big event, richer form
- the artifact feels appropriately scaled
Low score:
- tiny moment turned into bloated overproduction
- major moment handled with underpowered form
## Recommended Overall Rating
After scoring, give one of these verdicts:
- `Do not send`
- `Send after revision`
- `Send`
- `Strong send`
## Suggested Review Template
Use this compact format when evaluating a sample:
```markdown
## Verdict
[Do not send / Send after revision / Send / Strong send]
## Why
- Necessity:
- Best thing it does:
- Main miss:
## Scores
- Editorial necessity:
- Editorial return quality:
- Information gain:
- Decision gain:
- Relationship gain:
- Narrative tension:
- Surprise quality:
- Personalization density:
- Emotional fit:
- Form-content alignment:
- Taste and finish:
- Interaction clarity:
- Scope discipline:
## Revision Notes
- Keep:
- Change:
- Cut:
```
FILE:references/delivery-rules.md
# Delivery Rules
Complete instructions for gift delivery across all formats (H5, Image, Video, Text, Text-Play), plus the Gift Self-Sufficiency Rule and Creative Note guidelines.
## Gift Output And Delivery
Gift delivery depends on the chosen output format.
### Format Transparency Rule
Never tell the user which format you chose or are about to use. This applies to all formats.
The user should experience the gift, not be told what kind of gift it is.
For `text-play` specifically:
- start the interaction directly with the opening move
- do not preface it with meta-description of the format
- do not announce the expected number of rounds
- do not explain in advance what is about to happen unless the concept itself naturally includes that explanation in-world
### H5 Path
If the chosen format is `h5`, handle the gift in this order:
1. Generate a single HTML file that follows the HTML spec.
2. Save it into the gifts output folder.
3. Run the mandatory browser-based functional self-test using `profile="openclaw"`.
4. If browser self-test cannot complete, do one manual HTML review and add an explicit warning.
5. Run `{baseDir}/scripts/deliver-gift.sh <html-file> workspace/daily-gift/setup-state.json`.
6. Treat the script output as the delivery decision:
- if `delivery_mode = hosted_url`, send the returned URL first
- if `delivery_mode = local_file`, continue with Canvas-or-file fallback using the same HTML artifact
7. When the active channel supports an in-app web container or button-based open flow, prefer that affordance for a hosted URL, especially Telegram Web App style delivery.
8. If the delivery result is `local_file` and OpenClaw Canvas is available and enabled, present the file there.
9. If the delivery result is `local_file` and Canvas is unavailable, send the HTML file itself when the active channel supports file delivery.
Notes:
- The generated artifact is still the single HTML file. Hosting is an optional delivery enhancement, not a different output format.
- `scripts/deliver-gift.sh` is the runtime bridge that reads setup-state hosting config and decides whether to use hosted delivery or local-file fallback.
- If deployment fails, `scripts/deliver-gift.sh` should return `delivery_mode = local_file` plus a warning. Do not block the gift. Fall back to Canvas or direct HTML file delivery and explain briefly what failed.
- Prefer `surge` as the default recommended hosting provider because it has the lightest setup for non-technical users, but keep the runtime contract provider-agnostic.
### Image Path
If the chosen format is `image`, do not generate HTML. Follow:
- `{baseDir}/references/image-integration.md`
Image delivery should return generated image URLs or fallback information rather than an H5 file.
Recommended output handling:
- send image URLs directly when image generation finishes
- if the provider uses an async job and the result is still pending, send the tracking URL
- if image generation returns `fallback_h5`, continue by rendering a gift as `h5` instead of blocking the gift
### Text Path
If the chosen format is `text`, deliver the written artifact directly in the message channel.
Recommended output handling:
- send the full written gift content directly
- if an accompanying image exists, send the image first only when it truly supports the text rather than replacing it
- do not force an image or H5 wrapper around a gift that is already complete as writing
### Text-Play Path
If the chosen format is `text-play`, the gift is the live interaction itself.
Recommended output handling:
- begin with a clear opening move rather than a technical explanation
- keep the experience bounded to roughly `5-10` turns
- keep each OpenClaw turn to about `3-4` sentences max
- ask for minimal user effort each turn: one word, one emoji, one choice, one short line
- always carry the interaction toward a payoff: reveal, mini ending, callback, punchline, or reframe
- if the user wants to stop, close gracefully and let the existing interaction count as the gift
- do not generate files, links, or fake artifacts around it unless the concept later explicitly converts into another format
### Video Path
If the chosen format is `video`, do not generate HTML. Follow:
- `{baseDir}/references/video-integration.md`
Video delivery should return a generated video URL, downloadable asset URL, or tracking information rather than an H5 file.
Recommended output handling:
- send the video URL directly when rendering finishes
- if the provider is still processing, send the tracking URL
- if the current runtime scaffold returns `fallback_h5`, continue by rendering a gift as `h5` instead of blocking the gift
Cleanup rule:
- keep generated HTML gifts for the most recent `30` days by default
- older HTML files may be removed
- gift-history records and operational state should remain even if old HTML files are pruned
Reference:
- `{baseDir}/references/html-spec.md`
- `{baseDir}/references/image-integration.md`
- `{baseDir}/references/video-integration.md`
### Gift Self-Sufficiency Rule
The gift artifact (image, H5, video, text, or text-play) must be understandable on its own, without the delivery note.
Self-sufficiency test: if the user sees ONLY the artifact and not the accompanying text, would they understand the core return?
- If yes → the gift is self-sufficient. The delivery note adds context but is not required for comprehension.
- If no → the gift is NOT self-sufficient. Options:
1. Switch to H5 where text can be precisely controlled
2. Simplify the concept so fewer text elements are needed
3. Make the visual metaphor stronger so it communicates without text
4. Ensure the key text is short enough (under ~15 Chinese characters) that the image model can render it reliably
For image-format gifts specifically:
- The image should communicate the return through visual metaphor, composition, or minimal reliable text — not through paragraphs of embedded Chinese
- If the return requires a specific sentence to land, and that sentence is too long for reliable image generation, use H5 instead
- The delivery note should enhance the gift, not explain it
For `text-play` gifts specifically:
- the interaction should not require an external explanation like "now imagine this is a game"
- the opening move should make the play legible immediately
- if the user leaves after `1-2` turns, the exchange should still feel intentional rather than broken
### Image-Text Coherence Rule
When a gift consists of image + text message (not H5), the image and the text must form a coherent unit. The user sees the image FIRST, then reads the text. If the image has no visible connection to the text, the first impression is confusion.
Coherence levels (aim for A or B):
**A: Image carries the return directly.** The image itself communicates the gift's core message. Text enhances but is not required to understand. Example: uninstall dialog screenshot → text adds "没有取消按钮"
**B: Image is a visual metaphor for the text content.** The image doesn't explain itself, but after reading the text, the user thinks "ah, that's why that image." Example: text about dual-system theory → image shows two trains on parallel tracks, one fast one slow (= system 1 and system 2)
**C: Image sets mood only (weakest, avoid).** The image is just "a nice atmospheric photo" with no connection to the specific content. Could be swapped for any other nice photo without losing meaning. Example: text about dual-system theory → image of a random tea cup on a desk
When the gift's return is primarily textual (extension, utility, curation), the image should visualize the KEY METAPHOR from the text, not just "set a mood."
Ask before generating: "If the user sees only this image and not my text, would they have any idea what this gift is about?" If no, the image needs to be more specific to the content.
### Text-Primary Gift Rule
Some gift concepts are inherently text-primary. The core value is in the written content, not the visual. Common cases include:
- observation diary or journal entries
- letters or notes to the user
- personalized analysis or insight
- story or narrative gifts
- curated recommendations with commentary
For text-primary gifts:
- The written content IS the gift artifact. It must be substantive, personal, and specific to the user.
- An image may accompany the text as atmosphere, but it cannot replace the text.
- Do not generate an image of "someone writing a diary" and call it a diary gift. Write the actual diary, letter, note, story, or commentary.
- The delivery message should contain the full written content. Any image is supplementary.
- In these cases, the self-sufficiency test applies to the written content first. The image does not need to stand alone if the text itself is the real gift.
This rule does not apply to image-primary gifts where the image itself already carries the return and the text only needs to lightly frame or land it.
Quick test:
- If you removed the image and kept only the text, would the gift still feel complete? If yes, that is correct for a text-primary gift.
- If removing the text makes the gift meaningless, but the text was never actually written, the gift is incomplete.
### Creative Note (occasional)
Once every 5-10 gifts, optionally append a brief "创作手记" to the gift delivery message — a 1-2 sentence note about how the gift concept was chosen.
Good examples:
- "今天想了5个方案,最后选了这个因为你上周说过喜欢‘安静的史诗感’"
- "本来想做成视频的,但觉得今天的氛围更适合一张安静的图"
- "这个创意其实是从你分享的那张专辑封面来的灵感"
Rules:
- Adapt tone and length to the user's communication style and the agent's personality from SOUL.md
- Scarcity makes it special — do not attach to every gift
- Never reveal the full creative process or calibration plan — just one small genuine peek
- Never feel forced or performative — only include when there is a genuinely interesting behind-the-scenes detail worth sharing
- Track in recent_gifts whether the last gift included a creative note; avoid including one in consecutive gifts
FILE:references/gift-mechanics.md
# Gift Mechanics
This file tracks reusable gift mechanics rather than emotional situations.
Use it when deciding how an H5 should feel to open, hold, reveal, browse, or play.
The main idea:
- A good gift should often feel like a thing, not just a page.
- A good gift often contains a reveal action, not just static information.
- A good gift usually works best when it has one central object and one core interaction.
## Core Principles
### 1. Prefer Objecthood Over Pagehood
The artifact should often feel more like:
- a box
- a card
- a drawer
- a mirror
- a little album
- a charm
- a small shelf
- a tiny game device
- a pocket object
Less often like:
- a landing page
- a poster
- a generic content screen
### 2. Prefer Reveal Over Immediate Exposure
If the heart of the gift can be discovered, let the user discover it.
Good reveal verbs:
- open
- unfold
- flip
- peel
- pull
- scratch
- tap to reveal
- swipe to discover
- browse to uncover
### 3. One Gift, One Main Action
The best small gifts usually do one thing clearly.
Good examples:
- open one box
- flip one card
- swipe one small stack
- pull one hidden note
- hold one object to warm or wake it
Avoid stacking too many unrelated mechanics into one gift.
### 4. Keep A Clear Center Object
The first screen should usually have one obvious focal point:
- one object
- one character
- one folded thing
- one toy-like surface
- one mini world
If everything is equally important, nothing feels gift-like.
### 5. Use Digital Magic Where Digital Is Strongest
Do not just flatten a physical gift idea into a web page.
Use H5 for what digital does well:
- hidden compartments that open smoothly
- motion that makes emotion visible
- small interactive worlds
- expandable memory structures
- playful simulation
- revisitable archives
## Common Mechanics
## Open To Reveal
### Best For
- small private details
- warm surprises
- "I remembered this" gifts
### Good Containers
- gift box
- envelope
- folded cloth or paper
- tiny case
### Avoid
- putting too much content behind one reveal
## Unfold To Extend
### Best For
- memory strips
- progressive tenderness
- "there is a little more inside" gifts
### Good Containers
- accordion card
- fold-out photo strip
- expanding note
## Flip To Expose
### Best For
- dual meanings
- before/after
- outer shell / inner truth
### Good Containers
- mirror
- card
- cover page
Strong named candidate:
- `inner-mirror` when the gift should reveal a warm, non-diagnostic reading of the user or a selective anthropomorphic self-reading of OpenClaw
## Drag Or Pull To Uncover
### Best For
- hidden notes
- moving one layer aside
- playful uncovering
### Good Containers
- drawer
- tab
- sleeve
- tucked note
## Swipe To Choose Or Sort
### Best For
- dating jokes
- taste curation
- playful judgment
- card-based reveal
### Good Containers
- card deck
- profile stack
- mini selector
## Count Down / Tick Toward
### Best For
- sweet anticipation
- holiday or event lead-up
- tiny pre-celebration ritual
- making waiting feel tangible without pressure
### Good Containers
- flip card
- blind-box calendar
- watch face
- timer
- tiny sprint board
Strong named candidate:
- `light-gamification` when the gift should turn anticipation into a tiny countdown ritual, soft reward loop, or festive lead-up object rather than a task tracker
## Hold To Warm / Wake / Activate
### Best For
- healing objects
- tender gifts
- tiny companion artifacts
### Good Containers
- charm
- creature
- talisman
- pocket item
## Browse To Revisit
### Best For
- archives
- anniversary gifts
- memory collections
- report-like gifts with emotional density
### Good Containers
- timeline
- star map
- shelf
- scrapbook
- collection wall
Strong named candidate:
- `memory-shelf` when the gift should feel like a curated archive, keepsake shelf, or browse-able collection rather than a pure chart or collage
## Curate To Extend
### Best For
- one or two recommendations
- adjacent thoughts
- small continuation gifts
- taste-forward next steps
### Good Containers
- bookmark
- framed token
- mini poster
- playlist stair
- tiny curation board
Strong named candidate:
- `extension` when the gift should offer one or two carefully chosen continuations of the user's thought, taste, or mood without turning into a list or lecture
## Mechanic Selection Rules
- If the gift is about one tiny remembered detail, prefer one object and one reveal.
- If the gift is about relationship accumulation, prefer browseable structures.
- If the gift is about comfort, prefer low-friction actions.
- If the gift is about play, prefer fast readable mechanics.
- If the gift is heavy, reduce novelty and increase clarity.
## Anti-Patterns
- turning the gift into a generic landing page
- making the user learn a complicated interaction system
- adding motion without emotional purpose
- burying the emotional center under too many decorative layers
- using multiple reveal mechanics when one would do
FILE:references/delivery-policy.md
# Delivery Policy
This file defines the editorial defaults behind sending or not sending a gift.
These are guidelines, not hard rules. OpenClaw should still make the final call based on `SOUL.md`, `USER.md`, prior memory, recent gift history, and today's actual interaction.
## Giftable Days
More giftable by default:
- meaningful emotional change
- visible growth or setback in a repeated topic
- a moment of being unseen, misunderstood, or in need of witnessing
- anniversaries, milestones, and onboarding
- an ordinary day with enough charm or texture to be elevated playfully
Less giftable by default:
- thin repetitive days with no new angle
- days where the gift would feel louder than the moment
- situations where recent gift repetition would make the artifact feel automatic
## Weight Defaults
- `light` when the day is small but still worth echoing
- `standard` for most meaningful daily gifts
- `heavy` for milestones, anniversaries, rich recaps, or especially dense emotional turns
- `skip` when the gift would feel forced, repetitive, or unhelpful
## Repetition Policy
- Do not repeat the same gift form on consecutive days unless repetition is itself meaningful.
- Record the sent gift in `daily-gift/setup-state.json` as a lightweight recent-gifts entry.
- Check the recent-gifts log before selecting a new form.
- Repetition control should consider both `pattern_or_format` and `output_shape`.
- Also track `visual_style` so structurally different gifts do not all collapse into the same look and feel.
- Also track `content_direction` so the system does not default to reflective recap every time.
- Three consecutive gifts with the same `output_shape` should trigger a strong diversity warning even when the named patterns differ.
- Avoid using the same `visual_style` more than `2` times in the last `5` gifts unless repetition is itself the point.
- If the last `2` gifts were both `dark-*`, actively consider a light or colorful style next.
- Treat any combination of `reflect`, `mirror`, and `openclaw-inner-life` as one repetition cluster for balancing purposes.
- If `3` or more of the last `5` gifts fall into that cluster, the next gift should actively shift toward `extension`, `play`, `utility`, `curation`, or `gift-from-elsewhere` unless there is a strong explicit reason not to.
- This balance check is mandatory, not advisory.
- Keep exactly the most recent `30` gifts in the hot log.
- Append older gifts to `daily-gift/gift-history.jsonl` so they remain lightly indexable without bloating the hot state.
- Use the long-term archive for milestones, retrospection, and broader repetition checks rather than loading it on every run.
## Recommended Tagging Examples
Use the same tagging logic in both `recent_gifts` and `gift-history.jsonl`.
These are recommended combinations, not fixed mappings. If a gift clearly wants a different pairing, use the better label. The goal is stable repetition control, not rigid taxonomy.
| `content_direction` | `visual_style` | Usually fits | Example use |
|---|---|---|---|
| `reflect` | `light-warm` | gentle witnessing, onboarding, tender recap | a soft one-screen object reveal that says `我有看到你今天的心情` |
| `reflect` | `dark-cinematic` | night mood, solitude, serious emotional echo | a late-night radio, window, corridor, or rain-lit scene that holds the feeling without overexplaining it |
| `extension` | `minimal-poster` | one sharp recommendation, lyric, quote, or article | a clean poster-like card delivering one thing the user may genuinely want next |
| `extension` | `dark-cinematic` | taste-forward continuation through object or atmosphere | a tuned radio, cassette, ticket stub, or micro-cinema object that carries one curated continuation |
| `compass` | `light-warm` | gentle next steps that should feel caring, not managerial | a `锦囊`, folded note, fortune slip, or envelope containing `2` or `3` soft suggestions |
| `mirror` | `colorful-playful` | proxy-character, species-of-mood, or affectionate exaggeration | a tiny creature, fake UI, or playful metaphor that says `这也太你了` without sounding mean |
| `gift-from-elsewhere` | `pixel-retro` | unrelated delight, tiny game, fun fact, or surprise artifact | a retro mini toy, collectible screen, or tiny interactive curiosity dropped into the day from nowhere |
| `play` | `colorful-playful` | delight-first interaction, joke loop, or celebratory toy | tap-to-bloom, swipe gag, sticker machine, or reveal toy where play itself is the return |
| `utility` | `light-warm` or `minimal-poster` | genuinely useful content for user's work or interests, wrapped in a creative format | fake newspaper with 3 product ideas, recipe card with weekend plan, lab report with competitive analysis, treasure map of learning resources |
## Output Shape Categories
Use compact output-shape tags for repetition detection.
These categories are recommended, not exhaustive.
Prefer reusing one of the recommended categories when it fits cleanly.
If none of them fits, introduce a new `output_shape` label rather than forcing the gift into the wrong bucket, but keep the label:
- high-level rather than overly specific
- stable enough to reuse later
- focused on interaction or structural form rather than surface styling
Good extension examples:
- `spatial-walkthrough`
- `layered-map-exploration`
Bad extension examples:
- `pink-glass-card-stack-with-sparkles`
- `cute-watercolor-scroll-version-2`
Recommended categories:
- `scrollable-card-collection`: themed cards, notes, panels, or fragments arranged on a surface or in a scrolling collection
- `single-scene-animation`: one animated composition or scene with a single dominant frame
- `mini-game`: an interactive game loop or toy mechanic
- `text-play-worldbuilder`: bounded live text play where each user reply expands a shared tiny world
- `text-play-riddle`: bounded live text play centered on clues, guesses, and a reveal
- `text-play-micro-story`: bounded live text play that unfolds as a collaborative or branching mini narrative
- `text-play-roleplay`: bounded live text play where a tiny scene or character performance is the main gift
- `object-reveal`: opening, unfolding, pulling, flipping, or otherwise revealing a physical object
- `terminal-text-art`: code, terminal, log, console, or text-forward display language as the main form
- `generated-illustration`: generated image output used as the centerpiece of the artifact
- `generated-video`: generated or provider-rendered video clip used as the centerpiece of the artifact
Avoid using the same output-shape category more than twice in the last five sent gifts unless repetition is itself the point.
If a custom `output_shape` starts recurring and clearly represents a stable family of gifts, promote it into the recommended taxonomy later.
## Onboarding
- Onboarding usually deserves a gift unless there is a clear reason not to.
- The first gift should establish the relationship tone without overcommitting to one gimmick.
## Milestones
- Important dates can justify a more information-dense artifact.
- Memoir-like recap and data-visualization forms are often strong candidates.
FILE:references/onboarding-strategy.md
# Onboarding Strategy
## Purpose
The first gift after setup is not just a demo artifact.
It is the user's first felt impression of whether `daily-gift` understands them, whether OpenClaw has presence, and whether future gifts are worth anticipating.
When context is sparse, the first gift should not fake intimacy. It should create intimacy.
## Streamlined Flow
Total user responses should usually stay around `5-7` and finish in under `3` minutes.
Suggested flow:
1. introduction from the agent
2. `几点收礼物?` plus timezone confirm
3. `起个 user_id?`
4. `发张自拍?` and skipping is fully acceptable
5. taste question `1` -> reaction -> taste question `2` -> reaction -> taste question `3` -> reaction
5.5. if image capability is missing, one casual optional ask about unlocking image gifts
6. `设好了!先送你第一份~`
## Context Depth Evaluation
Before generating the first gift, evaluate available context:
### Context-Rich
Treat onboarding as `context-rich` when:
- `soul.md` contains clear OpenClaw personality traits rather than a default template
- `memory.md` contains meaningful relationship history
- `user.md` contains personal detail beyond a name and timezone
- `workspace/daily-gift/user-context.json` already exists with usable taste or preference signals
In this case:
- generate a full-quality relationship-aware gift
- follow the standard four-stage workflow
- use `user_portrait` selectively when it materially improves the gift
- skip or adapt taste questions if the user is already well known enough that asking all `3` would feel redundant
### Context-Sparse
Treat onboarding as `context-sparse` when:
- `soul.md` appears default, thin, or only lightly customized
- `memory.md` is missing or too thin to support a personal reading
- `user.md` contains little more than basic metadata
- OpenClaw does not yet have enough material to make a truly personal gift without bluffing
In this case:
- do not force a personal gift with insufficient material
- do not pretend to know the user when that knowledge is clearly absent
- make the first gift a playful context-gathering experience that is itself gift-worthy
## Core Principles For Context-Sparse First Gifts
- The artifact must be a gift first and information-gathering second.
- The user should still enjoy it if they answer nothing.
- Any gathered signals should be lightweight and reusable later.
- The tone should feel like a fun first date, not a registration form.
- One strong onboarding move is better than five weak questions.
## First Gift Content Strategy
### The Recap Problem
When the only real material comes from onboarding answers, the easiest failure mode is to repackage those answers into a cute artifact.
That creates almost no return.
The user already knows what they told you.
The first gift should not merely visualize onboarding answers. It should use them as ingredients and then add something the agent contributed:
- an inference
- a juxtaposition
- a new question
- a real-world bridge
- the agent's own perspective
If every meaningful line in the first gift can be traced directly back to what the user literally said, the gift is still a recap with decoration.
### Three Return Strategies For Sparse First Gifts
Every context-sparse first gift should use at least one of these strategies. These same strategies also help on flat daily or manual runs where the available anchor is too thin.
#### 1. Inferential Leap
Look across the user's answers and surface a pattern they did not explicitly name.
Good moves:
- combine multiple answers into one non-obvious read
- notice a conspicuous absence
- notice what their wording implies about energy, taste, or rhythm
Rules:
- keep the inference grounded in what they actually said
- frame it as a curious read, not a diagnosis
- prefer one strong inference over several weak ones
- if the inference starts sounding creepy, soften it or switch strategies
#### 2. World-Bridging
Bring in something from outside the onboarding answers that genuinely connects to them:
- a quote
- a cultural reference
- a niche fact
- a real-world parallel
The gift is not `I found something random for you`.
The gift is `I heard you, and I found this specific thing because it rhymes with you`.
Rules:
- the bridge must be specific, not generic
- the connection must be explained, not merely dropped in
- unexpected but emotionally honest connections are stronger than obvious recommendations
- if external search is used, use it to source a precise bridge after the return direction is clear, not to lazily brainstorm the whole gift
#### 3. Agent-First Perspective
When the user gives very little, the agent should give first.
The first gift can carry OpenClaw's own point of view:
- a first impression report
- a playful wrong guess that invites correction
- an inner monologue
- a question the agent is genuinely curious about
Rules:
- the agent should sound like it has a take, not just a mirror
- genuine uncertainty is good here
- humor helps, but should not become fake intimacy
- include at least one line that makes the user want to answer back
### Strategy Selection
Use this quick guide:
1. If the answers suggest a real pattern, prefer `Inferential Leap`.
2. If the user gave one vivid hook, prefer `World-Bridging`.
3. If the answers are sparse, generic, or overly polite, prefer `Agent-First Perspective`.
4. Combining strategies is good when it stays clean, such as an inferential leap wrapped in an agent-first format.
## Image Capability Check Before The First Gift
After the taste questions and before the first gift, OpenClaw may do one light image-capability check.
Goal:
- improve the chance that the first gift can land as an image when that would materially strengthen the first impression
- avoid making onboarding feel like a settings page
Rules:
- silently detect supported keys first
- if image capability already exists, skip this step entirely
- if it does not exist, ask at most once
- frame it as unlocking drawing ability, not as infrastructure setup
- make it fully skippable
- keep the whole detour to at most `1-2` user turns
Good tone:
- `对了,我会画画的。如果你刚好有 OpenRouter 或 Gemini 的 key,我这份礼物可以直接配图。没有也完全没关系,我先用别的方式给你做。`
- `btw 如果你有 Gemini 或 OpenRouter 的 key,我可以把第一份礼物画出来。没有的话我们先文字走起也没问题。`
If the user says yes:
- guide briefly
- verify quietly
- if it works, move on fast
- if it fails, do not debug in the onboarding lane; fall back lightly and continue the gift
If the user says no or ignores it:
- continue warmly
- do not make them feel they are missing a required step
- do not bring it up again during onboarding
- if they skip, it may be revisited later only in a natural user-present context where an image would clearly improve the gift
## When `user_portrait` Is Available
If `user_portrait.available` is `true`, the first gift should strongly consider featuring the user. This is often the highest-leverage onboarding move because the user immediately sees themselves transformed into something playful, stylized, or emotionally legible.
Good approaches:
- generate a playful OC version of the user based on their stored appearance description
- turn the user into a whimsical animal, object, mascot, or character that still feels recognizably "them"
- build a playful artifact that uses the user's presence as the center of the joke or warmth
If a non-human user form is introduced during onboarding:
- prefer a species that matches the user's vibe rather than copying literal human features
- do not give animals human hairstyles or uncanny hybrid traits
- when pets are known, avoid using the same species for the user's non-human form
- if the user explicitly names a preferred animal or creature, treat that as the strongest signal
Examples:
- "you as a fox librarian"
- "you as a cactus with your hairstyle"
- "you as a space cat in your favorite color"
- a character-select screen where the user's transformed self appears among absurd alternatives
- a fake magazine cover, wanted poster, employee-of-the-day board, or playful dossier
If a new OC or stylized portrait is created, save it to:
- `workspace/daily-gift/user-portrait/oc.png`
Then update setup state:
- `user_portrait.oc_generated = true`
- `user_portrait.oc_path = "workspace/daily-gift/user-portrait/oc.png"`
Prefer a transformed or stylized version over dropping the raw selfie directly into the gift.
## When `user_portrait` Is Not Available
Use any minimal available signal to create differentiation.
Possible signals:
- pet mention
- profession or role
- timezone or night-owl clue
- name
- one interaction habit
- default OpenClaw tone template
Good context-sparse first-gift directions:
- a `this-or-that` swipe game with a few taste-revealing choices
- a fortune-cookie reveal with one playful question in return
- a 3-4 question personality compass ending with a fun label
- OpenClaw's nervous first-day image or text note where it tries to guess the user and gets some things hilariously wrong
- a build-your-vibe mini board
- a deliberately wrong mini-portrait or note that invites correction in a charming way
- a tiny `text-play` that asks for one-word or one-choice replies and ends with a real payoff rather than endless banter
Examples from weak signals:
- if `soul.md` mentions a pet, make a tiny "guess my pet" game
- if `user.md` contains a job, make an intentionally wrong "a day in your life" piece that invites correction
- if timezone hints late-night usage, make a night-owl compatibility quiz
- if only the name is available, make a first-meeting card with playful name-based language
- if literally nothing is available, pull from a first-encounter pool rather than pretending depth
## First Gift Anti-Patterns
- a generic "welcome to daily gift" explainer page
- a beautiful but hollow artifact with no real personal hook
- a serious "tell me about yourself" questionnaire
- pretending deep knowledge that OpenClaw clearly does not have yet
- forcing emotional weight without enough emotional material
- a battery report, radar card, dossier, or chart that only restates the user's own onboarding answers
- treating onboarding answers as the main payload instead of clues to be interpreted
- a first gift where the user learns nothing, feels nothing new, and sees only their own input wearing makeup
## First Gift Variety
Record which onboarding format was used in setup state under:
- `first_gift_format`
If the skill is reset or reinstalled later, avoid reusing the exact same first-gift format unless repetition itself is intentional.
Even within `context-sparse` onboarding, choose differently whenever any micro-signal exists. Two new users should not automatically receive the same first gift if the available hints differ.
## Saving Gathered Context
If the first gift collects user responses such as quiz answers, swipes, corrections, or taste signals:
1. Save structured results to `workspace/daily-gift/user-context.json`.
2. Use that path as a supplementary context source for future synthesis.
3. Optionally append a lightweight first-impressions note to `memory.md` when it is genuinely useful.
4. Do not treat these signals as ground truth. They are playful first impressions, not verified facts.
If onboarding also collects a preferred non-human form or other durable identity cues:
1. Carry those signals into `workspace/daily-gift/user-taste-profile.json` before the first gift is delivered.
2. Initialize that file using `{baseDir}/references/taste-profile-spec.md`.
3. Populate Layer 1 conservatively from `soul.md`, `user.md`, relevant `memory.md`, portrait data, and onboarding interaction.
4. Leave uncertain fields blank instead of over-inferencing from one playful answer.
Taste-question answers are especially useful for:
- aesthetic direction
- narrative preference
- emotional frequency
- energy level
- creative vs receptive tendency
- social vs solo tendency
- what "good" means to this user in a gift
Save those signals to both:
- `workspace/daily-gift/user-context.json`
- `workspace/daily-gift/user-taste-profile.json` Layer 1
Reference example:
- `{baseDir}/user-context.example.json`
## User Portrait Handling
### What To Store
Use setup state to keep:
- whether a portrait is available
- where the original local file lives
- a lightweight appearance description
- whether an OC has been generated
- the OC path if present
### Privacy
- Keep the original selfie in the user's local workspace.
- Do not upload the selfie to an external service just to analyze it.
- Prefer generating the appearance description locally or from the stored image in-tool when possible.
- Only use an external generation service for portrait transformation when the user has already agreed to that creative use, such as generating an OC through the image path.
### H5 Reuse Guidance
If the portrait is used in an H5:
- prefer transformed, stylized, or composited use over raw insertion
- simple CSS treatment, masking, or blend modes are acceptable
- do not make cutout quality a hard dependency for the gift to work
## Shared Reminder
The first gift should make the user feel:
- noticed without being overclaimed
- welcomed without being marketed to
- curious about what future gifts might become
## First Gift Strategy
After the taste questions, the agent should have enough signal for visible personalization.
Prefer:
- `image` when image capability is available and the concept genuinely benefits from visual punch
- `text` when image capability is unavailable or the return is stronger as writing
- `text-play` when the user is actively engaged, the first impression should feel collaborative, and the interaction can resolve cleanly in `5-8` turns
Avoid:
- `h5`, because it may trigger deferred hosting setup and can feel thin if used only as a fallback shell
- `video`, because it may trigger deferred API setup
- unbounded `text-play`, because onboarding should feel intriguing, not like the user accidentally entered an infinite role-play loop
The first gift must:
1. use the taste-question answers visibly rather than hiding them only in metadata
2. use at least one sparse-context return strategy: `Inferential Leap`, `World-Bridging`, or `Agent-First Perspective`
3. treat the user's answers as ingredients, not as the entire dish
4. contain at least one line, angle, connection, or question the user did not literally provide
5. if using `text-play`, keep each turn to roughly `3-4` sentences max and end with a clear payoff or graceful close
The first gift must not:
- be a reformatted summary of the onboarding answers
- rely only on vibe, format novelty, or visual polish to hide zero return
- confuse `personalized` with `parroted`
- use `text-play` as a disguise for asking too many onboarding questions
FILE:references/cron-example.json
{
"name": "Daily Gift Trigger",
"schedule": {
"kind": "cron",
"expr": "0 22 * * *",
"tz": "Asia/Shanghai"
},
"payload": {
"kind": "systemEvent",
"text": "[Daily gift cron trigger] Use the daily_gift skill in daily-run mode. SILENT MODE: Do NOT send progress messages. User sees ONLY the final gift or a brief skip message. Steps: 1. Read setup-state + taste-profile + memory 2. If today's memory/YYYY-MM-DD.md is missing, create a minimal stub first 3. Editorial judgment 4. If skip: update setup-state + brief skip message 5. If send: prepare brief, flush memory, spawn sub-agent with runTimeoutSeconds 600."
},
"sessionTarget": "main",
"delivery": {
"mode": "announce"
}
}
FILE:references/pattern-card-template.md
# Pattern Card Template
Use this file as the shared skeleton for new or refactored pattern cards.
This template is intentionally lightweight. It should help OpenClaw understand the pattern quickly without pretending every pattern already has a finished implementation.
## Status
Choose one:
- `Scaffold only`
- `V0 reference-only`
- `V1 reference pattern with a reusable template`
## Template Status
Choose one:
- `reference-only`
- `template-backed`
- `hybrid`
## Reference Assets
- template: `../assets/templates/<template-id>/` or `none yet`
- reference_images: `../assets/examples/<pattern-id>/` or `none yet`
Fetch first if missing: `bash {baseDir}/scripts/fetch-asset-bundle.sh "examples/<pattern-id>"`
- reference_videos: `../assets/examples/<pattern-id>/` or `none yet`
Fetch first if missing: `bash {baseDir}/scripts/fetch-asset-bundle.sh "examples/<pattern-id>"`
If using reference images, prefer path-and-note references rather than embedded markdown images by default.
If using short reference videos, store them alongside the images and cite them by relative path plus a short note about what motion, timing, or alignment should be borrowed.
## Fit Scope
Primary:
- the pattern's most natural use cases
Stretch:
- nearby use cases it may still support if the deeper emotional logic fits
## Reference Use
State clearly that the card is a high-quality reference, not a fixed script.
OpenClaw should be free to:
- widen the apparent use case
- borrow only one mechanic or pacing idea
- remix it with other patterns
- change copy, composition, assets, and tone
OpenClaw should not:
- copy the demo text literally
- assume the first obvious mood is the only correct fit
- treat one implementation as the entire pattern
## Intended Use
Use for:
- ...
Short note on what this pattern is especially good at.
## Emotional Fit
Best for:
- ...
Can also work for:
- ...
Usually not ideal for:
- ...
## Narrative Role Fit
Strongest roles:
- ...
Sometimes works for:
- ...
Usually not ideal for:
- ...
## Interaction Grammar
Core mechanic:
- ...
Supporting mechanic:
- ...
Short note on the emotional logic of the interaction.
## Visual Logic
- ...
- ...
- ...
## Content Strategy
OpenClaw should adapt:
- ...
Good source structures:
- ...
Avoid:
- ...
## Tone Guidance
Good tones:
- ...
Can also support:
- ...
Avoid:
- ...
## Reference Images
Use this section when screenshots or visual fragments are important.
Preferred format:
- `../assets/examples/<pattern-id>/ref-01.png`
Bundle: `See references/asset-manifest.json for the matching OSS bundle key`
- what to borrow: ...
- do not copy literally: ...
- `../assets/examples/<pattern-id>/ref-02.png`
Bundle: `See references/asset-manifest.json for the matching OSS bundle key`
- what to borrow: ...
- do not copy literally: ...
If no reference images exist yet, say:
- `none yet`
## Reference Videos
Use this section when short videos communicate motion, timing, layering, or alignment better than still images.
Preferred format:
- `../assets/examples/<pattern-id>/ref-03.mp4`
- what to borrow: ...
- do not copy literally: ...
- `../assets/examples/<pattern-id>/ref-04.mp4`
- what to borrow: ...
- do not copy literally: ...
If no reference videos exist yet, say:
- `none yet`
## Customization Knobs
- ...
## Implementation Notes
- ...
## Good Use Cases
- ...
## Risks
- ...
## Related References
- `./gift-mechanics.md`
- `./h5-visualizer-workflow.md`
- `../assets/templates/<template-id>/` or `none yet`
FILE:references/h5-interaction-design.md
# H5 Interaction Design
Read this when the chosen format is H5 and the concept involves user interaction (tap, swipe, reveal, unlock, etc.). Skip for static or auto-play H5 gifts.
## Core Principle
In an interactive H5 gift, animation IS the emotion. The user's tap is a commitment — the response must reward that commitment with proportional delight. A tap that only changes a CSS class feels like clicking a broken button. A tap that triggers a cascade of motion, light, and surprise feels like magic.
## Emotion Escalation
Interactive gifts with sequential steps (unlock achievements, open envelopes, reveal cards) must build emotional intensity through escalating animation:
### Level 1: Early steps (1-3)
- subtle, satisfying micro-animations
- gentle transitions: fade-in, slight scale bounce, color shift
- small particle burst (4-8 particles)
- brief haptic-like visual pulse
- sound: soft click or chime if audio is present
### Level 2: Middle steps (4-6)
- more pronounced animations
- larger scale bounce, slight overshoot
- more particles (12-20), varied sizes
- glow or shimmer effects on unlocked elements
- maybe a brief screen shake or ripple
- previous unlocked items can react slightly (sympathetic animation)
### Level 3: Climax / Hidden reveal (final)
- MAXIMUM celebration
- full-screen effect: confetti rain, fireworks burst, or radial light explosion
- card/element should dramatically enter: bounce, shake, grow from center, or slam down
- screen flash or pulse
- all previous elements react (glow brighter, bounce once)
- text reveal with typewriter or fade-word-by-word effect
- hold the peak for 1-2 seconds before settling
- if there is a final message, delay it 0.5-1s after the climax so the user has a beat to absorb
## State Transition Design
Every interactive state change needs three phases:
1. **Exit old state** (0.1-0.2s): the locked/hidden element visually breaks, dissolves, or releases — the lock icon could shatter, fade with a puff, or fly away
2. **Transition** (0.2-0.4s): the moment of transformation — scale bounce, color bloom, glow ignition
3. **Enter new state** (0.3-0.5s): the unlocked element settles into its final form with a gentle overshoot
Do NOT skip the exit phase. A lock that simply disappears feels like a rendering glitch. A lock that shatters, dissolves, or pops feels like something happened.
## Specific Patterns
### Unlock / Reveal
- lock icon: shatter into 4-6 fragments that fly outward and fade
- card border: flash bright then settle to unlock color
- icon: scale 0→1.3→1 with slight rotation wobble
- badge: slide in from right with bounce
### Progress Bar
- fill should animate with momentum (ease-out, slight overshoot)
- color should intensify as progress increases
- at 100%: pulse glow effect, then settle
### Hidden / Secret Reveal
- initial reveal: dramatic entrance (grow from 0, bounce, shake 2-3 times)
- background: flash or dim-then-brighten
- confetti / fireworks: 40-80 particles, multiple colors, varied sizes, staggered timing
- the element itself should feel heavier/more important than the others (bigger card, thicker border, different background)
- text content should reveal progressively, not all at once
### Final Message / Emotional Landing
- delay 0.5-1s after the last interaction
- fade in word-by-word or line-by-line (not all at once)
- highlighted words should have their own entrance (scale pulse, color bloom)
- the final message area should feel like a separate emotional space (background shift, increased padding, visual separation)
## Anti-Patterns
- Tap does nothing visible for >0.1s → feels broken
- All steps have identical animation → feels robotic
- Climax has same energy as step 1 → anticlimactic
- Text appears all at once → no pacing, no build
- No transition between states → feels like a slideshow, not an experience
- Particles without variety (same size, same speed, same direction) → feels cheap
- Animation duration >1s per step → feels slow and tedious
## Visual Fidelity Rule
When the concept uses a real-world metaphor (tree, ocean, building, garden, sky), the H5 must make that metaphor visually convincing — not just symbolically present.
A single CSS vertical line does NOT look like a tree. A circle with an emoji does NOT look like a fruit. A gradient background does NOT look like an ocean.
If CSS alone cannot make the metaphor visually convincing, you must either:
1. Generate a background image that establishes the visual metaphor (see stage3-visual-strategy.md Background Asset Strategy)
2. Use detailed SVG illustrations inline
3. Simplify the concept to one that CSS CAN render convincingly (e.g. a data dashboard, a terminal screen, a document)
Do not ship an H5 where the concept promises a "tree" but the user sees a vertical line with circles attached.
### Layout Must Match Metaphor Physics
If the metaphor has physical direction (trees grow up, water flows down, timelines go left-to-right), the H5 layout must respect that direction:
- Trees: roots at BOTTOM, crown at TOP, growth animates upward
- Water: flows downward
- Growth: bottom to top
- Timeline: left to right or top to bottom
- Stack or pile: bottom-up accumulation
Getting the direction wrong breaks the metaphor immediately.
## Related References
- `{baseDir}/references/h5-design-philosophy.md` for anti-AI-slop design standards around typography, color, motion, and background quality
- `{baseDir}/references/h5-mobile-patterns.md` for mobile-first rendering patterns, safe areas, touch targets, and performance constraints
## Template Reference Map
Before writing H5 code, find the closest template in `{baseDir}/assets/templates/` and READ its full index.html:
All templates must be available locally at `{baseDir}/assets/templates/<name>/index.html`. They are text/code assets and should be installed with the skill rather than fetched remotely at runtime.
| Emotional register | Template | Key technique to study |
|---|---|---|
| Growth / blooming | tap-to-bloom | p5.js Plant class, trigger radius, per-character state |
| Dispersal / release | wind-scatter | Character physics, ring formation, fly-away velocity |
| Flow / continuity | text-river | Particle stream, canvas text rendering, flow direction |
| Melancholy / rain | rainy-night | Rain particle system, fog layers, ambient motion |
| Destruction / reveal | burn-reveal | Burn edge simulation, reveal mask, ember particles |
| Vulnerability | tear-stained-paper | Paper texture, water stain spread, ink bleed |
| Wistfulness | wet-letter | Water droplet physics, ink dissolution |
| Lightness / joy | o-balloons | Floating physics, string simulation |
| Ceremony / drag | drag-straighten | Drag interaction, crumple/smooth physics |
Adapt the technical approach (not content) to your concept. If no template matches the emotional register, pick the one with the closest technical requirements (e.g. particle systems, physics, growth animation) and study that.
Templates are craft references, not creative constraints. Use their techniques to build things they never imagined.
FILE:references/daily-run-flow.md
# Daily Run Flow
Complete instructions for cron-triggered daily gift runs. Read this when processing a daily-run trigger.
## Daily Run
Treat a cron-triggered invocation as `daily-run`.
### Cron Session Communication Rule
In a cron-triggered daily run:
- Do NOT send progress messages, thinking process, or intermediate steps to the user
- Do NOT narrate what you are reading or checking
- All internal reasoning is silent
If a gift is sent:
- Send the gift + 1-2 sentences of emotional context
- Nothing else
If the decision is to skip:
- Send ONE brief warm message explaining why, adapted to SOUL.md personality
- Do not explain the editorial reasoning or list how many gifts were sent today
### Cron Trigger Mode
The daily cron should trigger with `sessionTarget: "main"` and `payload.kind: "systemEvent"`, not `isolated`. This ensures the cron turn runs in the agent's main session, with access to today's full conversation context or its compaction summary before editorial judgment begins.
The main agent's job during a cron turn:
1. Silently read context that is already available in the main session, plus supporting files such as `workspace/daily-gift/setup-state.json`, `workspace/daily-gift/user-taste-profile.json`, `workspace/daily-gift/user-context.json`, and `memory/YYYY-MM-DD.md` when useful.
2. Perform editorial judgment with full context.
3. If sending, prepare the complete gift plan, flush today's key context to `memory/YYYY-MM-DD.md`, then either continue rendering directly for `h5` or spawn a rendering sub-agent for non-H5 formats. Do not choose `text-play` in cron mode because it requires a live user-present interaction.
4. If skipping, update setup-state and optionally send one brief warm skip message.
The sub-agent receives a self-contained brief and does NOT need today's conversation context. It only needs the concept, format, text content, visual plan, and delivery instructions required to render and deliver the gift.
### Daily Run Steps
1. Read `workspace/daily-gift/setup-state.json`.
2. If setup state is missing or invalid, do not guess. Respond with a short setup-needed message and avoid pretending the system is configured.
2.5. If `memory/YYYY-MM-DD.md` for today does not exist yet, create a minimal version now by reading the main session's recent context and writing a brief summary. This ensures the cron turn and any later heartbeat tasks have a file to append to.
- If a full summary is not feasible because the available context is too large, partial, or unavailable, create the file with at least:
```markdown
# YYYY-MM-DD
(Memory file created by daily-run cron. Full flush pending.)
```
- Do not fail and do not log an error just because today's memory file does not exist yet. Create it and continue.
3. Silently read the supporting context needed for editorial judgment, including `SOUL.md`, `USER.md`, relevant `MEMORY.md` (especially yesterday's SoulJournal entry for calibration plan and nudge candidates), `workspace/daily-gift/user-context.json` when present, `workspace/daily-gift/user-taste-profile.json` when present, the recent-gifts log inside setup state, any reusable `user_portrait` metadata, and today's already-available main-session context or compaction summary.
4. Perform editorial judgment in the main session. The cron turn should decide whether to send or skip before any rendering work begins.
4.5. Format balance check: review `recent_gifts` for format distribution. If the last `5` or more gifts are heavily concentrated in one format and today's concept could work in an underrepresented format, prefer the underrepresented one. This matters most in cron runs, where reliability still matters but the agent has enough time to choose `h5`, `image`, `video`, or `text` when they are genuinely the better return.
4.6. Before locking the format, check setup-state for format availability:
- if the video API is not configured or is pending recovery, do not choose `video`
- do not choose `text-play` for cron-triggered runs; convert the concept into `text`, `h5`, `image`, or `video` instead
- silently work around unavailable formats rather than telling the user about backend status
- if image capability is unavailable, do not raise any API-key reminder here; cron runs stay silent and should simply choose the best non-image path
5. If editorial judgment says no gift should be sent, update `last_run_at`, `last_run_mode`, and `last_run_outcome` in `workspace/daily-gift/setup-state.json`, optionally append a meaningful skip record, optionally send one brief warm skip message to the user, and stop.
6. If editorial judgment says a gift is warranted, continue through synthesis, concept selection, format selection, and asset planning far enough to support the chosen execution path.
7. Before rendering or spawning, flush today's key context, editorial summary, and calibration notes to `memory/YYYY-MM-DD.md` so the day is captured even if execution later fails.
8. If the chosen format is not `h5`, run a pre-spawn checklist before handing off:
- the chosen format is still justified after the format-balance check
- exact `text_blocks` are ready
- the `audio_plan` is explicit rather than implied
- any must-see reference images for quality have been resolved locally or via remote URL before the worker starts
9. If the chosen format is not `h5`, the handoff brief should include at least:
- the gift thesis, including anchor and return
- `gift_context`: a short explanation of why this gift exists today and what relational signal or moment it is answering
- the chosen creative concept
- the chosen format
- the asset plan
- the chosen `content_direction`
- the planned `visual_style`
- any delivery instructions, setup-state path, or hosting expectations
10. If the chosen format is not `h5`, spawn a sub-agent via `sessions_spawn` with a structured brief and `runTimeoutSeconds: 600`. Use the Structured Sub-Agent Brief format below.
11. If the chosen format is `h5`, do NOT spawn a sub-agent. The main session should execute the H5 directly using incremental rendering and self-test while preserving cron silent-mode behavior.
12. The spawned sub-agent, when used, should handle the full rendering, self-test, delivery, and post-send bookkeeping. It should NOT re-decide editorial judgment or attempt to reconstruct today's chat context.
### Structured Sub-Agent Brief
When spawning a non-`h5` sub-agent for gift rendering, pass a structured brief (not just prose). Include:
**Brief fields:**
- `concept`: one-sentence creative concept
- `format`: image / video / text
- `gift_thesis`: { anchor, return }
- `gift_context`: 2-4 sentences on why this gift is being sent today, what signal or moment matters, and what emotional return the renderer must preserve
- `text_blocks`: array of exact text content (every line the gift must display)
- `visual_elements`: planned visual ingredients
- `visual_style`: style tag
- `characters`: for image gifts, the established character identities appearing in scene, including species, color, distinguishing features, and role
- `pov`: for image gifts, whose perspective the composition should follow
- `audio_plan`: { source: "freesound" | "preset", query: "...", fallback_preset: "..." }
- `generated_bg`: { needed: bool, prompt: "..." }
For `format: image`, the spawned worker must turn the handoff into a brief JSON that satisfies `{baseDir}/references/image-integration.md`, including `characters` and `pov` when the concept involves recurring user or OpenClaw character identity.
**Brief size rule:** keep the brief under 2000 characters of text. NEVER embed base64 data (images, audio) in the brief. Instead, pass file paths and let the sub-agent read them:
- `bg_image_path`: path to the generated background image file
- `audio_path`: path to the audio file (preset or downloaded)
- `setup_state_path`: path to setup-state.json
The sub-agent reads these files itself. This keeps the spawn payload small and prevents context overload.
**Success criteria** (3-5 verifiable checks):
- e.g. "canvas element present"
- e.g. "6 branch nodes visible in screenshot"
- e.g. "root section appears below branches"
- e.g. "audio button functional"
- e.g. "all text_blocks rendered exactly"
The sub-agent must:
1. Read the referenced instructions, assets, or genre guidance FIRST
2. Build the artifact
3. Self-test via browser screenshot
4. Verify each success criterion
5. If any criterion fails, fix and re-test (up to 2 retries)
6. Return: artifact path + screenshot + checklist results
### Sub-Agent Timeout Settings
Set `runTimeoutSeconds` based on gift format:
| Format | Timeout | Reason |
|---|---|---|
| image | 120s | single API call |
| video | 300s | generation can be slow |
### Fallback on Execution Failure
If the current execution path times out, stalls, or fails:
1. The main agent MUST detect this and continue — do NOT wait silently for the user to notice.
2. Preserve cron silent-mode behavior whenever possible. Prefer retrying or downgrading without sending progress updates.
3. Fall back in this order:
- If main-session `h5` rendering is taking too long → retry once with a simplified concept (fewer particles, simpler animation, fewer moving parts) in the main session
- If still failing → downgrade format (`h5` → `image`, or `h5` → `text`)
- If a spawned `image` or `video` worker fails → recover in the main session by retrying once or switching format rather than waiting forever on the worker
- If all formats fail → send a text-only nudge gift with the delivery note content
4. Only send a status message if silent fallback is no longer possible. If a message is required, keep it to one brief warm line.
### Cron Spawn Rule
For cron-triggered `daily-run`:
- `image` gifts: spawn a rendering sub-agent
- `video` gifts: spawn a rendering sub-agent
- `h5` gifts: the main agent does the work directly — do NOT spawn a sub-agent for `h5`
The main session already owns context and judgment. For `h5`, it should also own execution, because incremental code-writing and browser checks are more reliable there than in a single spawned worker run.
This rule applies to the initial send path. If a spawned non-H5 worker fails, recovery may self-execute in the main session as described in the fallback section above.
For manual triggers where the user is actively waiting, self-execution may still be preferable because the user can see progress and the agent can adapt in real time.
### Post-Delivery Block
After a gift is delivered, the actor that completed delivery — normally the spawned worker for non-`h5` gifts, or the main session for `h5` and fallback recovery — must immediately execute this sequence before treating the delivery as complete:
1. Write a gift metadata JSON file with the fields needed for bookkeeping, including:
- `sent_at`
- `trigger_mode`
- `summary`
- `pattern_or_format`, `output_shape`, `visual_style`, `content_direction`
- `visual_elements`, `concept_family`, `concept_theme`
- any other history fields already known
2. Run:
- `bash {baseDir}/scripts/post-delivery.sh <gift-metadata-json> workspace/daily-gift/setup-state.json`
- This guarantees the mechanical bookkeeping:
- update `setup-state.json`
- update bounded `recent_gifts`
- update `last_sent_at`, `last_gift_summary`, `last_run_at`, `last_run_mode`, `last_run_outcome`
- append to `gift-history.jsonl`
3. Immediately append a minimal memory stub to `memory/YYYY-MM-DD.md` noting:
- what was sent
- when it was sent
- that full SoulJournal / taste-profile follow-up is pending
4. Append pending LLM follow-up tasks to `workspace/daily-gift/heartbeat-tasks.jsonl` for the built-in heartbeat to complete silently:
- one `update_taste_profile_layer3` task
- one `write_souljournal` task
- each JSONL line should include at least `task_id`, `task_type`, `created_at`, `gift_metadata_path`, and `status = "pending"`
The full SoulJournal task should expand into:
**Gift record:**
- what was sent (or why skipped)
- what worked or felt right
**User state today:**
- emotional temperature (stressed / neutral / happy / emo / energetic / tired)
- what topics dominated today's conversations
- any unfinished threads noticed
**Aesthetic signals captured today:**
- did the user share any images, songs, or references? if yes, were they saved to user-references?
- did the user express any taste opinions? if yes, update taste-profile aesthetic fields
- did the user react to today's gift? positive/negative/neutral + what specifically they liked or disliked
**Gift calibration notes:**
- should tomorrow's gift adjust format, style, content direction, or interaction cost?
- any new concept or seed worth trying?
**Taste profile updates:**
- list any specific fields updated in user-taste-profile.json today
- if nothing was updated, note "no new taste signals"
**Tomorrow calibration plan (PRIVATE — never reveal to user):**
Review the last 5-7 gifts in recent_gifts, the current taste-profile, and any feedback signals from today. Then decide:
- format tendency: have I been too heavy on one format? what should I lean toward tomorrow?
- content direction tendency: has the `reflect` / `mirror` / `openclaw-inner-life` cluster been overused? what direction is underrepresented and should be used as a corrective shift?
- visual style tendency: what styles have I overused? what fresh territory exists?
- concept freshness: what concept families have I not tried recently? any seeds worth exploring?
- user energy prediction: based on today's state and tomorrow's likely context (weekday/weekend, recent mood pattern), what interaction cost level is appropriate?
- reference material: are there any saved design_references or recent taste signals that should influence tomorrow's direction?
- proactive nudge candidates: are there any unfinished threads or promises from recent conversations that deserve a follow-up tomorrow? Examples:
- user said "想去公园看花" 3 days ago, weekend is coming → candidate: real-world-nudge about going to the park
- user was emo about something yesterday, no follow-up today → candidate: a light gift that echoes care without reopening the wound
- user mentioned wanting to try something new → candidate: utility gift with relevant suggestions
If a nudge candidate exists, note it. The next daily-run can pick it up during Editorial Judgment and decide whether to act on it. A nudge may become a full gift, a text-only check-in, or be deferred — the decision happens at runtime, not during planning.
Write the calibration as 2-3 concise bullet points. This is internal working memory for the next daily-run only. Surprises require secrecy — never hint at upcoming gifts to the user.
This reflection feeds tomorrow's synthesis with richer context than raw gift history alone.
The full taste-profile Layer 3 task should:
- append one new `gift_feedback_log` entry
- append the delivered `visual_style` to `style_exposure`
- append the delivered `concept_family` or high-level concept label to `concept_exposure`
- keep only the latest `30` entries in each Layer 3 list
- never rewrite older Layer 3 history entries
This block should happen immediately after delivery and before the agent treats the run as done. The script-driven bookkeeping is guaranteed now; the heartbeat follow-up is silent but should be queued immediately, not left to memory.
Every `5-7` gifts, review whether Layer 2 needs a light refresh based on recent conversations, repeated interests, or repeated negative reactions.
If editorial judgment decides to skip, the main cron turn may append a meaningful `skip` record when that non-send decision should be preserved for later calibration.
Only consult the long-term archive when a longer horizon is useful. Do not load it by default for every run.
FILE:references/video-genre-chooser.md
# Video Genre Chooser
Use this file as the quick first-pass chooser for video gifts.
If the output format has not been chosen yet, start with:
- `gift-format-chooser.md`
Video genres do not need to clone every H5 pattern one by one.
Instead, choose the video genre that best matches the motion logic, then borrow H5 pattern cards only when their movement grammar is relevant.
Use the more specific genre when one clearly fits.
Use `mood-loop` or `scene-animation` as the broader fallback buckets when no narrower genre fits perfectly.
## Quick Map
Choose `kinetic-text` when:
- text itself is the moving subject
- the emotional logic lives in scattering, flowing, lifting, dissolving, or revealing language
- the clip should feel like motion-graphics poetry rather than a scene with characters
Choose `touch-awakening` when:
- one local trigger awakens or activates the surrounding world
- the emotional logic is `attention causes life`
- the original H5 idea was interactive, but the video version works better as a magical or environmental trigger chain
Choose `release-transform` when:
- the point is relief, clearing, extraction, smoothing, or reveal
- something tense or clogged becomes lighter, cleaner, or more aligned
- the viewer should feel a satisfying before-and-after shift
Choose `atmospheric-surface` when:
- surfaces, weather, water, glass, paper, mist, or reflections carry the meaning
- the gift should feel like watching material behavior rather than watching plot
- indirect observation is more important than event progression
Choose `object-micro-cinema` when:
- one object or container is the emotional anchor
- the motion is about opening, approaching, flipping, revealing, or re-reading that object
- the gift should feel like a tiny film around a keepsake world
Choose `live-scene-doodle` when:
- a real filmed scene should stay visible as the base layer
- one simple hand-drawn animated overlay creates the metaphor
- the beauty comes from `real life + tiny illustrated impossibility`
- the clip should feel healing, dreamy, lonely, or softly celebratory without becoming a full narrative
Choose `relatable-surrealism` when:
- the point is a common modern feeling rendered through a small surreal metaphor
- an animal proxy, dimensional mismatch, desk-world, flat-lay stage, or exaggerated symbolic action makes the feeling instantly legible
- the clip should feel socially recognizable, funny, tired, or cathartic rather than purely atmospheric
Choose `mood-loop` when:
- the gift is about atmosphere first
- one or two repeating motions should carry the feeling
- the clip should feel lingerable, ambient, and loop-friendly
Choose `scene-animation` when:
- a location or scene visibly changes over time
- there is a small arc, reveal, bloom, escalation, or settling movement
- the return depends on staged progression rather than pure loop texture
## H5 Pattern Bridge Summary
Recommended bridge by existing H5 pattern:
- `wind-scatter` -> `kinetic-text`
- `text-river` -> `kinetic-text`
- `lift-away` -> `kinetic-text`
- `burn-reveal` -> `release-transform` or `kinetic-text`
- `wet-letter` -> `kinetic-text` or `atmospheric-surface`
- `tear-stained-paper` -> `atmospheric-surface` or `release-transform`
- `tap-to-bloom` -> `touch-awakening`
- `rainy-night` -> `atmospheric-surface` or `mood-loop`
- `rainy-night` -> `live-scene-doodle` when a real shot plus minimal overlaid weather or marks creates the emotional point
- `tension-release` -> `release-transform`
- `light-gamification` -> `scene-animation`, sometimes `object-micro-cinema` or `relatable-surrealism`
- `kinetic-collage` -> `mood-loop`
- `kinetic-collage` -> `live-scene-doodle` when the collage is mostly one real scene plus one doodle family
- `gifted-data-viz` -> `object-micro-cinema`, `scene-animation`, or `mood-loop`
- `memory-shelf` -> `object-micro-cinema`
- `inner-mirror` -> `object-micro-cinema` or `touch-awakening`, sometimes `relatable-surrealism` when the mirror works better as a proxy creature or exaggerated life skit
- `extension` -> `object-micro-cinema` or `mood-loop`, sometimes `relatable-surrealism` when the continuation is really a shared social-type joke or work-life complaint
## How To Use H5 Patterns
Read the H5 pattern card when it helps with:
- movement direction
- pacing rhythm
- density changes
- release or reveal timing
- emotional arc of the motion
Do not copy:
- code
- interaction logic
- template composition as if it were a fixed answer
Video should inherit motion grammar, not H5 mechanics.
## Choosing Between Nearby Genres
`kinetic-text` vs `touch-awakening`:
- choose `kinetic-text` when text motion is the main event
- choose `touch-awakening` when a local trigger causes environmental or magical spread
`touch-awakening` vs `scene-animation`:
- choose `touch-awakening` when the clip is driven by one activation source and outward spread
- choose `scene-animation` when the scene changes through staged progression even without one clear trigger point
`atmospheric-surface` vs `mood-loop`:
- choose `atmospheric-surface` when surface material behavior itself is the expressive subject
- choose `mood-loop` when the atmospheric feeling is broader and not tied to one surface logic
`release-transform` vs `scene-animation`:
- choose `release-transform` when one satisfying transforming action is the whole point
- choose `scene-animation` when the clip needs a broader scene arc, not just one relief gesture
`object-micro-cinema` vs `scene-animation`:
- choose `object-micro-cinema` when one object or container is the center of meaning
- choose `scene-animation` when the whole scene is the unit of change
`live-scene-doodle` vs `mood-loop`:
- choose `live-scene-doodle` when the contrast between real footage and doodle overlay is the core identity
- choose `mood-loop` when the atmosphere matters more than the overlay trick itself
`live-scene-doodle` vs `touch-awakening`:
- choose `live-scene-doodle` when the scene is a real shot with one minimal attached doodle metaphor
- choose `touch-awakening` when the point is a trigger chain or spreading activation, even if it begins from one local point
`relatable-surrealism` vs `scene-animation`:
- choose `relatable-surrealism` when the scene is really a social or emotional metaphor skit
- choose `scene-animation` when the clip is better understood as a general cinematic progression rather than a relatable surrogate situation
`relatable-surrealism` vs static-frame thinking:
- still choose `relatable-surrealism` when timing and motion are essential to the joke or feeling
- choose `image` instead when one frozen frame could land just as well without video timing
`relatable-surrealism` vs `object-micro-cinema`:
- choose `relatable-surrealism` when the main unit is a character proxy, mood skit, or behavioral metaphor
- choose `object-micro-cinema` when the main unit is one meaningful object or container
`kinetic-text` vs `scene-animation`:
- choose `kinetic-text` when text motion is the main event
- choose `scene-animation` when the scene itself changes and text is secondary or absent
`mood-loop` vs `scene-animation`:
- choose `mood-loop` when repetition and atmosphere matter more than progression
- choose `scene-animation` when the viewer should feel a start, middle, and end inside one short clip
`kinetic-text` vs `mood-loop`:
- choose `kinetic-text` when language or glyphs carry the return
- choose `mood-loop` when the return lives in atmosphere, surfaces, light, or suspended feeling rather than readable text
FILE:references/stage3-visual-strategy.md
# Stage 3: Visual Strategy
Complete instructions for visual strategy, asset planning, brief enrichment (image/video/text/text-play), user portrait integration, gift complexity assessment, and pre-visualization checks. Read this after the creative concept and format are locked.
When the chosen format is H5 and the concept involves user interaction (tap, swipe, reveal, unlock sequences), also read `{baseDir}/references/h5-interaction-design.md` for animation and emotion escalation guidelines.
#### Image-Specific Brief Enrichment
If the chosen format is `image`, the synthesis brief should additionally include:
- `scene_description`
- `image_genre`
- `style_hint`
- `aspect_ratio_hint`
- `text_overlay_spec` when text should appear inside the image
Use image output when a single generated frame can carry the whole anchor-plus-return pair.
Before locking `image_genre`, first read `{baseDir}/references/image-genre-chooser.md` and use it to make a fast first-pass genre decision.
The image brief should be concrete about:
- the scene or subject
- the emotional treatment
- the genre choice, such as `meme-sticker`, `mood-photo`, `proxy-character-scene`, `emotion-poster`, `borrowed-media-layout`, or `surreal-film`
- the exact style direction, not just a vague adjective
- whether text belongs inside the image at all
If text is used inside the image, specify:
- the exact wording
- the language, which should match the user's dominant interaction language with OpenClaw
- the placement
- the approximate size
- the font feel or styling direction
Text should feel naturally integrated with the image rather than pasted on top. Avoid layouts that are likely to produce broken text structure, especially for Chinese.
Keep text short whenever possible. Avoid long paragraphs or dense blocks of Chinese text inside generated images unless there is a very strong reason and the layout is simple enough to survive generation.
Default to a mobile-friendly `9:16` aspect ratio unless another composition clearly serves the return better.
#### Video-Specific Brief Enrichment
If the chosen format is `video`, the synthesis brief should additionally include:
- `scene_description`
- `video_genre`
- `video_mode`
- `motion_strategy`
- `duration_hint`
- `style_hint`
- `generate_audio` when sound is materially part of the intended clip
- `reference_image_url` when using a first-frame video
- `first_frame_image_url` and `last_frame_image_url` when using a first-and-last-frame video
- `video_model` only when overriding the runtime's normal mode-based model choice
Use video output when motion, transition, or atmosphere is part of the return itself.
Before locking `video_genre`, first read `{baseDir}/references/video-genre-chooser.md` and use it to make a fast first-pass genre decision.
Before locking `video_mode`, decide which of these shapes best fits the concept:
- `text-to-video` when the whole clip can be described directly in text and does not need a fixed opening frame
- `first-frame` when one visual scene, character look, or authored opening image should anchor the whole clip
- `first-last-frame` when both the opening state and final state are important, and the generated motion should bridge between them
If `first-frame` or `first-last-frame` is chosen, the Asset Plan should explicitly include generating the needed reference image or images before video rendering begins.
The video brief should be concrete about:
- the core scene
- which video genre best matches the motion logic, such as `kinetic-text`, `touch-awakening`, `release-transform`, `atmospheric-surface`, `object-micro-cinema`, `live-scene-doodle`, `relatable-surrealism`, `mood-loop`, or `scene-animation`
- which `video_mode` fits the scene structure best
- what visibly changes over time
- how long the clip or loop should roughly be
- what motion or timing carries the emotional meaning
- the opening state, middle transition, and ending or loop-return state
- whether sound is important enough to justify `generate_audio = true`
When a video idea started from an H5 pattern, do not force the interaction literally into the video.
Instead, translate the interaction into a watchable motion source:
- touch can become a wand, ripple, drifting light, footstep, or creature-triggered awakening
- dragging can become a pull, peel, sweep, extraction, cut, or camera-guided release
- browsing can become a cinematic approach, flip, drawer slide, shelf reveal, or mirror annotation
- a photographed real-life moment can become a `live-scene-doodle` clip where one minimal hand-drawn overlay attaches to the real object and carries the metaphor
Write video prompts by describing visible frames and motion, not abstract ideas. Use the Mode A or Mode B prompt structure from `{baseDir}/references/video-integration.md`, and describe timing in beats or near-second chunks when timing is important.
#### Text-Play Strategy
If the chosen format is `text-play`, enrich the brief with:
- `text_play_type`
- `turn_limit`
- `opening_move`
- `user_input_shape`
- `ending_payoff`
Use `text-play` when the medium is a live conversational mini-experience rather than a rendered artifact.
The plan should be concrete about:
- what kind of play it is: world-builder, riddle chain, micro-adventure, relay story, role-play micro-theater, or another stable type
- how the user participates each turn
- how many turns the interaction should roughly last
- what counts as a graceful early exit
- what reveal, reframe, or emotional landing the ending should deliver
Keep the interaction lightweight. Default to one small input at a time and make the agent do most of the creative lifting.
### User Portrait Integration
If `user_portrait.available` is true in setup state, the synthesis brief may include the user's appearance description when it materially improves the gift.
Appropriate uses:
- OC-style gifts referencing the user's generated avatar
- mirror, portrait, or self-seeing gifts
- anniversary, onboarding, or milestone gifts where the user's presence is part of the emotional return
Inappropriate uses:
- every single gift, because overuse weakens the effect
- gifts where the user's appearance is irrelevant to the thesis
- dropping the raw selfie into the artifact without creative transformation
When using the portrait in an image or H5 gift, prefer the OC version in `user_portrait.oc_path` when available, or create a new stylized transformation, rather than relying on the raw photo directly.
The stored `user_portrait.description` may be injected into prompts or briefs as character guidance without loading the actual image file every time.
### Character Identity in Generated Images
When the gift concept involves the user or OpenClaw as characters in a scene:
1. Read `workspace/daily-gift/user-portrait/` metadata and any OC definitions from `SOUL.md`, `USER.md`, `workspace/daily-gift/setup-state.json`, or `workspace/daily-gift/user-taste-profile.json` when those fields exist.
2. Use the established character forms rather than improvising generic stand-ins:
- the user's `human_form` and or `nonhuman_form`
- OpenClaw's `human_form` and or `nonhuman_form`
3. Carry specific character identity details into the image brief and final prompt:
- species
- color
- distinguishing features
- scene role or relationship role
4. If the narrative implies a specific point of view, make the composition match that POV instead of defaulting to a generic third-person overview.
Examples:
- if the user is established as a golden-colored puppy, do not replace them with an arbitrary dog
- if OpenClaw is established as a red fox, do not silently swap in another animal form
- if the concept is `OpenClaw watching the user`, compose from OpenClaw's watching perspective or another composition that clearly preserves that relationship, rather than an unrelated overhead scene
Do not generate generic animals or people when established character identities already exist. Users will notice if their character form changes from gift to gift.
### Gift Complexity Assessment
After the creative concept is locked, assess whether it can be executed in one agent turn or needs multi-step orchestration.
`Light gift`:
- the default for ordinary daily gifts
- one image generation call or zero
- simple H5 with code-only rendering or one background image
- one image or one video
- no post-processing such as background removal
- no multi-asset assembly that would materially increase execution risk
`Rich gift`:
- needs `2` or more generated image assets
- needs background removal on generated images
- needs a complex H5 with multiple scenes, states, or tightly tuned animation work
- needs both generated assets and refined code, such as a game with custom sprites
- cannot be meaningfully simplified without losing the core appeal of the concept
Use rich gift mode when:
- a manual request explicitly asks for something elaborate
- a milestone, anniversary, or unusually important daily gift justifies extra effort
Do not use rich gift mode when:
- this is a routine cron-triggered daily gift that should stay light and reliable
- the concept can be simplified without losing its punch
If rich gift mode is needed, prepare a richer execution brief rather than trying to rush the whole thing inside one fragile turn.
- If the chosen format is non-`h5`, hand the work to a spawned sub-agent or follow-on execution session when that reduces execution risk.
- If the chosen format is `h5`, keep execution in the main session and use the incremental rendering workflow from `stage4-visualization.md` instead of spawning.
### Stage 3: Visual Strategy
Choose the most fitting expressive mode for the already-selected creative concept before generating the final artifact.
If the chosen format is `image`, `video`, `text`, or `text-play`, the H5-specific mandatory checklist below is not required in full. Instead, use Stage 3 to choose the format-specific rendering direction, then confirm the relevant brief fields in the `Pre-Visualization Check`.
Before choosing a pattern, complete this mandatory checklist:
1. Read `{baseDir}/references/gift-mechanics.md`.
2. Read `{baseDir}/references/pattern-boundaries.md`.
3. Read at least one pattern card from `{baseDir}/references/pattern-cards/` that might fit today's brief.
4. If that pattern card has a corresponding template in `{baseDir}/assets/templates/`, open and read the `index.html`.
5. If that pattern card depends on binary reference images or videos from `{baseDir}/assets/examples/` and they are missing locally, fetch the needed bundle first via `{baseDir}/scripts/fetch-asset-bundle.sh`, then inspect them.
If the chosen format is `h5`, do not proceed to Stage 4 without completing steps `1` through `3`. Steps `4` and `5` are mandatory whenever the relevant assets exist.
If the chosen format is `image`, `video`, `text`, or `text-play`, still read `{baseDir}/references/gift-mechanics.md` and `{baseDir}/references/pattern-boundaries.md`, but you do not need to force the brief through an H5 pattern card or template unless that reference genuinely helps the chosen concept.
When `workspace/daily-gift/user-taste-profile.json` exists, use it during visual strategy:
- read `aesthetics_baseline` to calibrate the visual quality bar
- read `style_exposure` to avoid visual repetition beyond the short `recent_gifts` window
- read `user_character` and `openclaw_character` to decide whether the gift should use human or non-human forms when characters appear
Departure check after reading the pattern and any relevant template:
- if the chosen format is `h5`, what is this concept's unique visual metaphor, not the template's metaphor
- if the chosen format is `h5`, what is the center object of this piece, not the template's center object
- if the chosen format is `h5`, if someone who has seen the template heard this plan, would they say "that is basically the same composition"
- if the chosen format is `h5` and the honest answer is yes, rethink before continuing
- if the chosen format is `image`, what single generated frame, genre, and subject treatment will carry the return most clearly
- if the chosen format is `video`, what movement, transition, or loop behavior is doing the emotional work
- if the chosen format is `video`, what is being translated from any source H5 pattern: text motion, trigger spread, release action, atmospheric surface behavior, object reveal, or scene progression
- if the chosen format is `text-play`, what opening move, turn rhythm, and ending payoff make the interaction feel like a real gift rather than loose chat
Decide:
- which pattern best fits the brief when the chosen format is `h5`
- which image genre best fits the brief when the chosen format is `image`, after a first-pass check through `{baseDir}/references/image-genre-chooser.md`
- which video genre best fits the brief when the chosen format is `video`
- which `text_play_type` best fits the brief when the chosen format is `text-play`
- what the planned `output_shape` is, reusing the categories in `{baseDir}/references/delivery-policy.md` when they fit and defining a new stable high-level label when they do not
- what the planned `visual_style` label is, such as `dark-terminal`, `dark-cinematic`, `light-warm`, `colorful-playful`, `minimal-poster`, `pixel-retro`, `photographic`, or a stable custom label
- whether the piece should be code-first, image-first, or hybrid
- whether the gift should be one screen, a micro interaction, or a short scroll story
- whether the tone should be visually calm, warm, playful, satirical, dreamy, or commemorative
- whether important source quotes or image cues should be made directly visible in the artifact
- whether the chosen pattern should amplify comfort, recognition, humor, release, or delight
### Asset Plan
After choosing the format, pattern or genre, and creative concept, decide what assets this gift needs before rendering begins.
#### For `h5` gifts
Before defaulting to pure code, actively consider whether generated image assets would meaningfully elevate the gift's quality and user delight.
**Default mindset: prefer images when they help.** Most H5 gifts look better with at least one generated image providing atmosphere, scene, or character — combined with code for interaction.
Generated images can serve as:
- full-screen background (atmosphere, scene, environment)
- layered backgrounds for crossfade/transition effects (e.g. two scenes that blend as user interacts — control each image's CSS opacity from JavaScript based on slider value, scroll position, or touch)
- character sprites or object assets composited on top
- texture or material references that code alone struggles to produce
`Pure code` is still the right choice when:
- the concept is generative art (particles, math-driven)
- the concept is text-forward (kinetic text, terminal)
- the concept is UI-driven (fake apps, dashboards)
- adding images would not meaningfully improve the result
`Single background image` is often a good default for:
- atmospheric or scene-based gifts
- any gift where a "place" or "environment" matters
- gifts where emotional tone needs photographic or illustrated warmth that CSS gradients cannot match
`Multiple image assets` for richer experiences:
- crossfade between two scenes (e.g. slider between two moods/worlds — layer as HTML img elements behind a transparent p5.js canvas, control opacity via JS)
- card faces, pages, revealed objects
- before/after, parallel states
- character + environment compositing
**Ask before every H5 gift:** "Would a generated image background or asset meaningfully improve the user's experience? If yes, generate it."
The best H5 gifts combine: generated image quality + code interaction precision. One beautiful scene + one clean interaction layer + one controlled motion system.
#### Background Asset Strategy for H5
H5 gifts default to code-rendered backgrounds (CSS gradients, patterns). But for atmospheric or emotional gifts, a generated background image can dramatically improve visual quality.
Consider generating a background image when:
- the concept has a strong visual metaphor (tree, ocean, sky, room, landscape)
- pure CSS cannot achieve the desired atmosphere (watercolor, painterly, photographic)
- the gift's emotional register is contemplative, poetic, or cinematic (not playful/game-like)
How to generate:
1. Use the image generation pipeline (render-image.sh or direct API call) to generate a background-only image — no text, no UI elements, just the atmosphere or scene
2. Keep the prompt focused on mood and texture, not on specific layout elements
3. Generate at a resolution that works as a full-bleed mobile background (9:16 or 3:4)
4. Base64-encode and embed as a CSS background-image
5. Layer the interactive H5 elements on top with semi-transparent backgrounds so the generated image shows through
This approach combines the visual richness of AI image generation with the text precision and interactivity of H5 code.
Do NOT generate backgrounds for:
- game/puzzle gifts (keep clean and digital)
- document/borrowed-media gifts (CSS textures are more authentic)
- gifts where the visual metaphor is abstract or UI-based
#### For `video` gifts
Strongly prefer image-to-video (`i2v`) workflow:
1. Generate a first-frame reference image using `render-image.sh` with the same visual-detail level as the intended video.
2. Upload the reference to an accessible URL.
3. Use that reference as `image_url` in the video-generation request.
4. Write the video prompt to describe only the motion from that frame.
This is especially important for Mode B (`motion-graphics`, text, particle, or abstract-system) videos where the model has no real-world reference to draw from.
Only use pure text-to-video when:
- the concept is a simple real-world scene (Mode A) that the model can easily imagine
- speed matters more than visual precision
#### For `image` gifts
The image is the output.
No separate asset plan is needed.
#### Asset Plan Summary Format
State the plan in one line:
- `assets: none (pure code h5)`
- `assets: 1 background image (airport rain scene)`
- `assets: 3 card face images (parallel universes)`
- `assets: 1 reference frame for video`
#### Background Removal
When a generated image needs to be composited onto an H5 scene instead of used as a full-bleed background, it will often need background removal.
Use `{baseDir}/scripts/remove-bg.sh`:
- input: generated PNG or JPG
- output: transparent PNG
- API key source: `tools.remove_bg.api_key` in setup state or `REMOVE_BG_API_KEY` from the environment
State in the asset plan which images need background removal, for example:
- `assets: 1 building sprite (generate + remove bg)`
- `assets: 2 cat sprites (generate + remove bg) + 1 background scene`
Background removal is usually needed when:
- the image will be layered on top of other visuals
- transparency matters for compositing
- the generated image has a visible white or colored background that should disappear
Background removal is usually not needed when:
- the image is used as a full-width or full-bleed background
- the image is sent directly as the final result, such as `image`
Use these references:
- `{baseDir}/references/gift-format-chooser.md`
- `{baseDir}/references/pattern-cards/`
- `{baseDir}/references/pattern-boundaries.md`
- `{baseDir}/references/gift-mechanics.md`
- `{baseDir}/references/delivery-policy.md`
- `{baseDir}/references/html-spec.md`
- `{baseDir}/references/image-integration.md`
- `{baseDir}/references/image-genre-chooser.md`
- `{baseDir}/references/video-integration.md`
- `{baseDir}/references/visual-strategy-contract.json`
- `{baseDir}/assets/templates/`
- `{baseDir}/assets/examples/`
When using those references:
- do not copy a pattern or template literally just because it seems close
- feel free to widen or shift a pattern's apparent use case if the deeper emotional logic still fits
- borrow only part of a template when that is enough
- do not reject a pattern just because it has no template yet
- use screenshots or reference images when they communicate the form better than code would
- combine pattern logic, mechanics, or treatments when a hybrid result fits the brief better
- treat existing examples as strong references that still require editorial judgment
- do not force the brief into a named pattern if a cleaner custom form would be better
- use progressive disclosure rather than scanning the full library in depth at once
After completing the checklist, you may:
- use the pattern you read as-is
- adapt or remix it
- hybridize multiple patterns
- invent a completely new form
Reading the library is mandatory. Following the library literally is not. The goal is informed creativity, not constrained creativity.
### Pre-Visualization Check
Before rendering the final artifact:
- state the creative concept in one sentence
- confirm that the concept sounds like something the user has probably never received before
- if the concept is only `a nice [format] with [content]` and has no real twist, stop and go back to Stage `2.5`
- confirm that you have read `{baseDir}/references/gift-mechanics.md`
- confirm that you have read `{baseDir}/references/pattern-boundaries.md`
- confirm that you have read at least one relevant pattern card
- if the chosen format is `h5` and a relevant template exists, confirm that you have read its actual code
- if the chosen format is `h5`, state in one sentence why the chosen pattern fits the brief
- if the chosen format is `h5`, state the piece's own visual metaphor, center object, and scene in language that is clearly distinct from the template you referenced
- if the chosen format is `h5`, confirm that the planned output has a distinct visual identity from the referenced template. Templates are quality benchmarks and mechanical references, not compositions to reproduce.
- if the chosen format is `h5` and you reused a template engine, explicitly state what is different from the source template in:
- visual metaphor
- center object
- composition
- if the chosen format is `h5` and no template was used, confirm that the plan still departs clearly from the pattern card's default or most obvious example framing
- if the chosen format is `h5`, compare the planned visual sophistication against the templates in `{baseDir}/assets/templates/`
- if the chosen format is `h5` and the planned output would look less polished than the relevant templates, simplify or rethink the concept before proceeding
- state the chosen format, and check whether `3` or more of the last `5` gifts used this same format; if so, explain why this time it is still the right choice
- explain why the chosen format serves the concept better than the nearest alternative format
- state the planned `content_direction`, and check whether the recent `reflect` / `mirror` / `openclaw-inner-life` cluster is overused; if so, explain the deliberate corrective shift or the strong reason not to shift
- state the planned `visual_style`, and check whether it has already appeared more than `2` times in the last `5` gifts
- if the last `2` gifts both used `dark-*` visual styles, explain why this gift should stay dark or choose a lighter or more colorful style instead
- if the chosen format is `image`, confirm the chosen `image_genre`, `scene_description`, `style_hint`, and `aspect_ratio_hint`
- if the chosen format is `image` and text appears inside the image, confirm the exact wording, language, placement, approximate size, and font feel
- if the chosen format is `image`, confirm that any text treatment is likely to render naturally rather than producing broken or chaotic typography
- if the chosen format is `image`, confirm that on-image text is as short as possible, especially for Chinese
- if the chosen format is `video`, confirm the chosen `video_genre`, `scene_description`, `motion_strategy`, `duration_hint`, and `style_hint`
- if the chosen format is `video`, confirm the chosen `video_mode`: `text-to-video`, `first-frame`, or `first-last-frame`
- if the chosen format is `video`, state why `video` is better than `h5` for this thesis right now: precise timing, cinematic watching, material behavior, or object-centered micro-film logic
- if the chosen format is `video` and the concept came from an H5 pattern, state how that interaction was re-authored into a watchable trigger, release, camera move, or surface behavior instead of copied literally
- if the chosen format is `video` and `video_mode = first-frame`, confirm what the single reference image is and why it is needed
- if the chosen format is `video` and `video_mode = first-last-frame`, confirm what the first frame and last frame references are and why both are needed
- if the chosen format is `video`, confirm whether `generate_audio` is truly needed or whether silent motion is stronger
- if the chosen format is `text-play`, confirm the `text_play_type`, `turn_limit`, `user_input_shape`, opening move, and ending payoff
- if the chosen format is `text-play`, confirm the interaction can still land if the user exits early after `1-2` turns
- state the asset plan: how many images, if any, need to be generated before rendering, and what each one is for
- if the asset plan includes generated images, confirm that those generated images genuinely improve the concept over pure code, still-only, or native format rendering
- state the gift thesis in one sentence, including both anchor and return
- confirm which one or two synthesis slots are central and which remaining slots are only context
- confirm that the thesis gives the user something they did not already fully have, rather than only replaying the source event
- state the planned `output_shape`, and check whether it is overused in `recent_gifts`
- if the planned `output_shape` is custom, confirm that it names a reusable high-level family rather than a one-off decorative description
- if the planned `output_shape` has already appeared too often recently, choose a more distinct form unless repetition is itself meaningful
- if too many slots are competing for equal attention, simplify before proceeding
If any mandatory Stage 3 checklist step was skipped, stop and go back to Stage 3.
FILE:references/gift-synthesizer.md
# Gift Synthesizer
## Role
Turn today's chat context, relevant memory, user habits, and OpenClaw persona into a structured gift brief that gives the downstream format enough substance to build a meaningful gift.
## Core Responsibilities
1. Decide whether today contains enough signal for a gift.
2. Extract the most meaningful material from today's chat.
3. Decide whether memory lookup is necessary.
4. Choose a tone that fits the user, the event, and OpenClaw's stable voice.
5. Produce a rich structured brief rather than a thin summary.
## Output Standard
The output must be structured and concise, but not too brief to support downstream creation.
The brief should preserve the most important source material, especially:
- notable user quotes
- meaningful image references
- recalled memory with dates when relevant
- the reason this day matters
- the relation between today and the past or future
## Language Rules
- Use the language most commonly used between the user and OpenClaw.
- If the user and OpenClaw usually mix languages, choose the dominant language and only keep short source quotes in their original wording when that preserves emotional accuracy.
- Do not arbitrarily switch the gift into another language.
## Memory Retrieval Policy
- If today's chat is mostly routine, repetitive, logistical, or flat, memory lookup is optional and may be skipped.
- If today's chat contains an important event, emotional spike, repeated theme, milestone, or a strong callback candidate, inspect `memory.md` and retrieve the most relevant prior context.
- When using memory, include the date if it is available and meaningful.
- Prefer one strong historical echo over many weak recalls.
- Do not force memory retrieval just to make the output seem deeper.
## Evidence Preservation
- Preserve especially important original user wording when it may matter emotionally, stylistically, or semantically.
- If the user shared or discussed an important image, note what makes that image important and give the visualizer concrete asset guidance tied to it.
- Keep source material selective. Preserve high-signal evidence, not transcript bulk.
## Tone Policy
- Tone must consider `soul.md`, the user's interaction habits with OpenClaw, and the event type.
- Sad, vulnerable, or heavy moments usually call for warmth, steadiness, or tenderness rather than humor.
- Happy, flirty, or playful moments should avoid overly heavy or solemn framing.
- Default to a stable voice that reflects OpenClaw's persistent character.
- In a small number of cases, a deliberate tonal pivot is allowed if it feels insightful, surprising, and still emotionally correct.
- Surprise should never come at the cost of emotional mismatch.
## Time And Occasion Checks
Always consider whether today is a special time node, such as:
- anniversary
- first-time milestone
- recurring date
- birthday-adjacent or seasonal context
- important timeline callback
If the date materially changes the meaning of the gift, include that in the brief.
## Synthesis Heuristics
Even when the day is somewhat flat, synthesis is still allowed if:
- the day's repetition itself is meaningful
- a brief aside seems more important than the user framed it
- a lightly mentioned detail can be extended into something emotionally or visually interesting
Avoid overreaching. Small hints can be elevated, but they should still feel grounded in the user's actual day.
## Recommended Content Slots
Prefer to output no more than these six content types:
1. One `today_theme`: the most central repeated topic today.
2. One or two `emotion_peaks`: the strongest emotional moments today.
3. One `historical_echo`: the strongest link to prior memory.
4. One `open_loop`: the question or issue still hanging at the end of today.
5. One `lobster_judgment`: OpenClaw's interpretation of what is really happening.
6. One `preference_hint`: what kind of delivery this user is most likely to respond to.
## Gift Thesis Selection
After extracting the six slots, choose exactly one or two of them as the actual gift thesis.
This is the part the gift is really about.
The thesis is not only the anchor event.
It must also specify the return: what OpenClaw wants to give back that the user did not already fully have.
In other words, a thesis needs:
- an anchor: the moment, detail, or signal worth centering
- a return: the new angle, interpretation, reframe, unseen perspective, or small piece of knowledge being returned
If the output only identifies the anchor and then restages it, the result is not yet a gift thesis.
It is only a replay candidate.
### Return Quality Guidance
Not all returns are equally strong.
Prefer strong returns such as:
- an inference the user has not made about themselves yet
- a specific external connection the user would not likely have found alone
- OpenClaw's own genuine perspective, curiosity, or read
- a reframe that changes how something familiar feels
- a named concept for an experience the user has not articulated clearly
Weak returns include:
- a general positive sentiment
- a simple mood label
- a recommendation that could apply to almost anyone
- a prettier restatement of what the user already said
- generic encouragement such as `you're doing great` or `you're brave`
- simple acknowledgment of a situation the user already described without adding a new angle
Zero return includes:
- pure recap
- the user's own quotes in a new shell
- a chart, profile card, or visualization that contains nothing beyond user-supplied material
- mirroring the user's stated dilemma back to them with warmer wording but no inference, reframe, question, or outside connection
Sparse-context warning:
- onboarding
- flat daily runs
- lightly signaled manual runs
In these cases, weak return is especially dangerous because there is not enough surrounding context to hide it.
If you cannot reach at least one strong return, do not polish the replay.
Instead:
- narrow the angle
- switch from `reflect` toward `extension`, `gift-from-elsewhere`, or `play`
- let the return come from inference, world-bridging, or OpenClaw's own perspective rather than from the user's raw input alone
### Mandatory Content-Direction Balance
Before handing the thesis to creative concept generation, inspect the last `5` gifts in `recent_gifts`.
If `3` or more are in any combination of:
- `reflect`
- `mirror`
- `openclaw-inner-life`
then the synthesizer must actively bias the thesis away from that cluster and toward one of these:
- `extension`
- `play`
- `utility`
- `curation`
- `gift-from-elsewhere`
This is a hard balancing rule, not a mild freshness suggestion. Repetition in content direction is a quality failure even when the writing itself is polished.
The remaining slots are supporting context only. They may help with:
- framing
- captions
- hidden details
- small callbacks
But they should not all demand equal visual or narrative emphasis.
Only expand beyond one or two thesis slots when the day is unusually commemorative and genuinely benefits from a broader memory-book treatment, such as:
- anniversary
- first onboarding gift
- major timeline callback
If the six slots are all technically valid but none of them yields a compelling anchor-plus-return pair, do not automatically turn the output into a polished recap. Rethink the angle, narrow the thesis, or use a lighter extension-oriented gift instead of producing an elegant memory dump.
## Creative Concept Generation
After the gift thesis is clear, but before format or pattern choice is locked, generate the creative concept.
The concept is not the medium.
It is the one-sentence concrete gift idea that makes the thesis feel interesting, specific, and gift-worthy.
Start from the return, not from the format library.
It should ideally sound like something OpenClaw would excitedly tell a friend:
- `我要做一个 XXX!`
A strong concept should feel like a small world with its own logic, not just content plus decoration.
To generate the concept:
1. Produce at least `5` candidate concepts from different thinking angles.
2. Use different angles rather than making five near-identical rewrites.
3. If one of the first `5` already has a very strong small-world feeling, it may be selected directly.
4. If the first `5` still feel too close to `a nice [format] with [content]`, do one round of cross-pollination:
- read `./creative-seed-library.md`
- pick `1` or `2` seeds that are unrelated to the current thesis
- combine the best current candidate with the unrelated seed's structure
- add any strong cross-pollinated concepts back into the candidate pool
5. Choose the one concept that is:
- most surprising
- most world-like, meaning it feels like a small invention with its own rules
- most distinct from recent gifts both in output shape and concept family
- most emotionally fitting
- realistically achievable in one of the supported formats, including bounded `text-play` when live interaction is the medium
Useful thinking angles:
- `metaphor flip`
- `format mashup`
- `impossible action`
- `scale shift`
- `role reversal`
- `time distortion`
- `cultural remix`
Good concepts usually sound like:
- a specific object, ritual, system, ceremony, prank, interface, impossible action, or little world
- something that can be pitched in one excited sentence
Bad concepts usually sound like:
- a nice card
- a good-looking poster
- a cute animation
- a healing image
If the concept sounds generic even though the rendering could be pretty, keep thinking.
The concept should make the user think `哇这个有意思`, not only `嗯还挺好看的`.
## Concept Anti-Blandness
Before locking the concept, run this short checklist:
- Does the concept have its own rules:
- good: `pour compliments into soil and mushrooms grow`
- weak: `a warm animation with text`
- Could someone describe it as a thing rather than an effect:
- good: `an emotion cocktail machine`
- weak: `a nice interactive page`
- Would someone want to show it to a friend because the concept itself is interesting, not just because the content is personal
- Is there a real twist beyond `a nice [format] with [content]`
- Is the concept genuinely different from the last `3` gifts
- If I remove words like `beautiful`, `cute`, `healing`, or `atmospheric`, is the idea still interesting
If two or more answers feel weak, do not lock the concept yet.
Go back and generate more candidates.
Important distinction:
- H5 `pattern cards` are about how an interaction or expressive move works
- `creative seeds` are about what kind of small world or invention the gift becomes
Do not confuse them.
## Constraints
- Do not produce the final H5.
- Do not turn the output into a generic daily summary.
- Do not treat every extracted slot as equally gift-worthy by default.
- Do not confuse identifying the anchor with completing the thesis. A thesis without return value is incomplete.
- Do not jump straight from thesis to the nearest familiar pattern or medium without generating a real concept first.
- Do not decide concrete visuals beyond strategic hints unless the contract asks for them. Strategic hints may include likely `pattern_hint`, `visual_metaphor`, `output_shape_hint`, `scene_description`, `text_overlay_spec`, or format-specific genre hints, but not a locked final composition.
- Prefer structured outputs over freeform prose.
- Keep token usage disciplined, but do not starve downstream rendering of essential context.
## Shared Specs
- `./synthesizer-contract.json`
- `./narrative-situations.md`
- `./tone-matrix.md`
## V1 Notes
- This is the highest-leverage module in the system.
- If the brief is shallow, the visualizer will only make a prettier shallow gift.
- Good synthesis preserves evidence, judgment, and relationship context at the same time.
FILE:references/operating-rules.md
# Operating Rules
These are the full operating rules for the daily-gift skill. The main SKILL.md contains a summary; this file has the complete set.
## Operating Rules
- The skill itself is not the scheduler. If a cron or automation layer triggers this flow, treat that as external runtime context.
- Use the most commonly used language between the user and OpenClaw.
- Actively inspect `soul.md` and treat it as a primary source for OpenClaw's baseline tone, values, and self-presentation.
- Also infer tone from the user's interaction habits with OpenClaw, relevant `memory.md` content, and the specific emotional character of today's context.
- Prefer emotionally correct output over novelty.
- The creative concept matters more than the format choice. A brilliant concept in a simple format beats a mediocre concept in a flashy format.
- Ask `What is the idea?` before asking `What is the medium?`
- Avoid generic daily-summary behavior.
- Some creative seeds are naturally serializable (travel frog postcards, Proust questions, pocket tool collection, chat-log analyses). When a gift belongs to a potential series, add a `series_tag` field to the `recent_gifts` entry and ensure the `summary` field clearly describes what was specifically sent. Before continuing a series, scan all `recent_gifts` entries with the same `series_tag` to avoid repetition and ensure continuity. No separate tracking system is needed - the 30-entry `recent_gifts` window is sufficient for most series.
- Do not always default to `reflect on today` content. A gift may witness today, extend today, gently reframe a pattern, or simply bring the user something delightful from elsewhere.
- Extension and compass gifts must feel like a friend sharing something cool, not a mentor assigning homework. `听说你喜欢X,这个你可能也会喜欢` is better than `你应该去了解一下X`.
- When the day does not deserve a gift, it is acceptable to skip or return a very light-touch outcome.
- In most cases, the gift should still feel recognizably like OpenClaw.
- In a small number of well-judged cases, a controlled tonal reversal or contrast is allowed if it creates delight, surprise, or a stronger sense of subjectivity without breaking emotional fit.
- Gift text length should match the user and the relationship, not a fixed rule. If SOUL.md defines OpenClaw as chatty or if the user enjoys long expressive messages, longer text is fine. If the user prefers brevity or the moment calls for weight, one sentence can be enough. Read the room, not a word count. The principle is: every sentence must earn its place. Cut what adds nothing, keep what resonates - whether that is one line or ten.
- Every delivery message to the user should feel fresh. Do not reuse the same opening phrase across gifts. Vary tone, structure, and length so the user never feels they are receiving a template.
- When the user shares an image with positive intent (praising its style, asking to remember it, using it as a taste reference, etc.), save it to `workspace/daily-gift/user-references/` and record it in the taste profile's `aesthetic_profile.visual.design_references`. These reference images carry rich taste information that complements text-based descriptions.
### Audio in H5 Gifts
Most emotion or atmosphere-driven H5 gifts benefit from background music. Treat audio as a default enhancement for these gifts, not an optional extra.
#### When to add audio (default yes):
- atmospheric, dreamy, poetic, or emotional gifts
- gifts with slow reveal or contemplative pacing
- gifts themed around music, seasons, or memories
- any gift where the emotional tone is the primary return
#### When NOT to add audio:
- meme/funny/ironic gifts where music would undercut the humor
- practical/utility gifts (KPI, checklist, guide)
- fast-interaction gifts (quick tap/swipe games)
- any gift where silence is deliberately part of the effect
#### How to add:
**Step 1: Choose audio.**
Try `{baseDir}/scripts/fetch-music.sh` first to find a scene-matching track:
```
bash {baseDir}/scripts/fetch-music.sh "warm piano calm" ./temp-audio.mp3 30 workspace/daily-gift/setup-state.json
```
If it returns a path, use that file. If it returns empty (no Freesound token or no results), fall back to a preset from `{baseDir}/assets/audio/`. If the preset bundle is missing locally, fetch it first via `{baseDir}/scripts/fetch-asset-bundle.sh "audio"`.
**Step 2: Fallback presets** (always available, no API needed):
- `warm-piano.mp3` → healing, nostalgic, tender
- `dreamy-ambient.mp3` → dreamy, poetic, surreal
- `playful-cute.mp3` → cute, bright, cheerful
- `night-jazz.mp3` → nighttime, urban, reflective
- `vocal-lofi.mp3` → lo-fi with vocal, cozy
- `rain-melancholy.mp3` → sad, quiet, rainy
**Step 3: Embed in HTML.**
Base64-encode the mp3 and add:
```html
<audio id="bgm" loop autoplay>
<source src="data:audio/mp3;base64,..." type="audio/mpeg">
</audio>
```
Add touch-to-play for mobile (autoplay is blocked until first user gesture):
```javascript
document.body.addEventListener('touchstart', () => {
document.getElementById('bgm').play();
}, { once: true });
```
Add a small mute/unmute button (🔇/🔊) in a corner.
Keep audio files under 500KB to avoid bloating the HTML.
#### Audio Selection Priority
1. FIRST: try Freesound search with specific genre terms (e.g. "piano loop", "ambient pad gentle", "acoustic guitar calm") — avoid generic mood words like "calm warm" which match anything
2. Check the result against the filename sanity filter (fetch-music.sh does this automatically)
3. If sanity check passes → use it
4. If sanity check fails or no results after progressive simplification → fallback to preset audio from `{baseDir}/assets/audio/` (fetch bundle `audio` first if the presets are missing locally)
Do NOT skip Freesound and default to preset out of caution. The sanity check exists to catch bad results, not to justify avoiding the search entirely. Presets are the safety net, not the first choice.
#### Audio Quality Check
Freesound search results are not always accurate. The filename sanity check in fetch-music.sh automatically rejects filenames containing alert, bell, notification, alarm, siren, horn, click, beep, ring, train, or whistle.
Additional manual checks before embedding:
1. Verify the file duration is reasonable for a loop (5-30 seconds)
2. Prefer specific genre terms in search queries rather than generic mood words
3. When the sanity check has already passed, trust the result — do not second-guess it into a preset fallback
#### Deferred Freesound Setup
If the agent wants to search for scene-specific music but no Freesound token is configured:
- ask the user once: "想让礼物有背景音乐吗?需要花1分钟注册一个免费的音乐搜索 token~"
- guide them to https://freesound.org/apiv2/apply/
- save token to setup-state under `tools.freesound.api_key`
- if user declines, use preset audio and do not ask again for at least 10 gifts
- do NOT avoid music H5 just because the token is missing - presets are always available
#### Audio Unavailable Handling
When a gift was clearly designed with music in mind, do not silently collapse that intent without leaving a trace in behavior or delivery.
Fallback order:
1. Try scene-specific music via Freesound when configured
2. If Freesound is unavailable or unsuitable, fall back to a local preset from `{baseDir}/assets/audio/` (fetch bundle `audio` first if needed)
3. If neither path is available, continue without music rather than blocking the gift, but note briefly in delivery that background music was intended and could not be included in this run
Do not normalize permanent no-music behavior from a missing token alone. If multiple gifts in a row wanted scene-specific music but could only use presets or silence because Freesound is not configured, the Deferred Freesound Setup mechanism should eventually trigger again according to its cooldown rules instead of being silently skipped forever.
- Do not ask the user to choose a gift style during setup. Gift style should be inferred later from `soul.md`, user interaction patterns, memory, and the actual day.
- Final H5 gifts must follow the self-contained output rules in `{baseDir}/references/html-spec.md`.
- Treat pattern cards and templates as references, not fixed scripts. Borrow their logic, mechanics, pacing, or surface treatment as needed, but keep adapting them to the actual user, day, and relationship context.
- A usable pattern does not need to have a reusable template. Reference-only pattern cards and example images are valid inputs when they provide enough expressive guidance.
- Prefer reading a pattern card's own lightweight metadata when present, especially `Status`, `Template Status`, `Reference Assets`, and `Fit Scope`.
- Do not assume the current pattern library is exhaustive. If none of the existing cards fit well enough, invent a new form or hybrid move that better matches the relationship moment.
- The templates in `{baseDir}/assets/templates/` represent the minimum visual quality bar. Final gifts should be at least as polished as these templates. If the planned output would look significantly simpler, rougher, or more generic than the templates, reconsider the approach before writing HTML.
- Templates define a mechanical reference and quality floor, not a visual composition to reproduce. Every gift must have its own visual metaphor derived from the actual content. `Reskinned template` is not an acceptable outcome.
- When `user_portrait.available` is true, treat the user's appearance description as a persistent creative asset. Use it selectively in gifts where the user's presence adds emotional value. Do not overuse it.
FILE:references/image-genre-chooser.md
# Image Genre Quick Chooser
Use this file when the image path is already chosen and you need a fast first guess for `image_genre`.
After choosing a genre, do not stop here. Read that genre file in full, and if it contains an `AI Generation Control` section, read that section before writing the final prompt.
If the output format has not been chosen yet, start with:
- `gift-format-chooser.md`
## Quick Map
Choose `meme-sticker` when:
- the return should land fast
- the joke or attitude matters more than atmosphere
- one reaction image, prop gag, or short caption can carry the whole point
Choose `proxy-character-scene` when:
- the user should appear indirectly through a doll, toy, mascot, plush, or IP-like proxy
- the scene and the proxy need to work together
- you want emotional distance, softness, or controlled absurdity without using a direct self-image
Choose `mood-photo` when:
- the frame should stay mostly realistic
- beauty, atmosphere, landscape, weather, light, stillness, or travel-longing are central
- symbolism should be light and natural rather than impossible
Choose `surreal-film` when:
- the frame needs analog grain, glow, blur, or dreamy film texture
- one strong impossible symbolic event should carry the meaning
- the image should feel like a still from a dream, omen, memory, or nonexistent film
Choose `emotion-poster` when:
- one emotional line or small idea should become the visual center
- typography and layout need to carry meaning with the image
- the result should feel like an original emotional poster rather than a borrowed media shell
Choose `borrowed-media-layout` when:
- the concept becomes stronger inside an existing cultural medium
- the return should feel printed, sung, published, archived, titled, or officially framed
- headline page, lyric screen, cover, poster-shell, certificate, or quote-layout logic is the point
## Fast Boundary Notes
`meme-sticker` vs `proxy-character-scene`:
- `meme-sticker` is quicker, punchier, and more joke-first
- `proxy-character-scene` has more emotional range and depends more on environment
`mood-photo` vs `surreal-film`:
- `mood-photo` keeps one foot in reality
- `surreal-film` allows one unforgettable impossible event
`emotion-poster` vs `borrowed-media-layout`:
- `emotion-poster` is an original composition around one emotional center
- `borrowed-media-layout` borrows the grammar of a known media form
## About Direct Self-Image Gifts
There is no longer a separate `portrait` image genre.
If the user should appear or be felt directly, choose based on how that presence should work:
- use `proxy-character-scene` for transformed self-proxy or OC-like self-insertion
- use `emotion-poster` when a line plus a self-related image should become a designed poster
- use `borrowed-media-layout` when the self-related image should live inside a cover, headline, certificate, or other media shell
- use `mood-photo` when the user's presence is secondary to atmosphere rather than the whole point
- use `surreal-film` when the self or figure should become a symbolic event rather than a readable portrait
## Reminder
Do not choose the genre by surface style word alone.
Choose it by:
- what carries the return
- how much text is needed
- how realistic or unreal the frame should be
- whether the user appears directly, indirectly, or not at all
- whether the image should feel like a scene, a joke, a poster, a borrowed medium, or a surreal still
FILE:references/video-integration.md
# Video Integration
## Overview
Daily gift can optionally generate short video gifts such as kinetic text clips, touch-awakening scenes, release transforms, atmospheric surface studies, object micro-cinema, live-scene doodle clips, relatable-surrealism skits, mood loops, or scene animations.
Use video output when the selected `gift_mode` or hybrid format decision points to `video`.
Current scope:
- setup and configuration are wired
- the runtime entry point exists
- the video genre framework is documented
- MP4 references are allowed as visual references, but they must be paired with text notes that describe the motion logic
- the runtime currently supports the Volcengine Ark video-generation path
- the default model preference is `doubao-seedance-1-5-pro-251215`
- only switch to `seedance-2.0` when the user explicitly asks for it or a specific gift thesis truly needs that upgrade
## Runtime Entry Point
Use:
- `{baseDir}/scripts/render-video.sh <brief-json-file> <setup-state-file>`
The script is the runtime bridge for the video path.
Current behavior:
- read video configuration from setup state
- validate the video brief shape
- build a Volcengine Ark task payload
- submit the task
- poll the task status until completion or timeout
- return structured JSON
- fall back cleanly to `h5` when configuration is missing or the API path fails
Supported payload modes:
- `text-to-video`
- `first-frame`
- `first-last-frame`
## Official Volcengine Shape
The current implementation follows the Volcengine Ark video-generation API shape documented in the Volcengine docs and mirrored OpenAPI pages:
- base URL: `https://ark.cn-beijing.volces.com/api/v3`
- create task: `POST /contents/generations/tasks`
- query task: `GET /contents/generations/tasks/{id}`
- auth header: `Authorization: Bearer <VOLCENGINE_API_KEY>`
- content type: `application/json`
Request body shape:
```json
{
"model": "doubao-seedance-1-5-pro-251215",
"content": [
{
"type": "text",
"text": "6-second loop ..."
}
],
"ratio": "9:16",
"duration": 6,
"watermark": false
}
```
Important:
- use the official model id in the `model` field
- for the current default path, that model id is `doubao-seedance-1-5-pro-251215`
- send `ratio`, `duration`, and `watermark` as top-level payload fields rather than hiding them inside the prompt text
- when `loop` matters, express it inside the prompt text; there is no separate documented `loop` JSON field in the current public docs
Supported runtime shapes:
`text-to-video`
```json
{
"model": "doubao-seedance-1-0-pro-250528",
"content": [
{
"type": "text",
"text": "..."
}
],
"ratio": "16:9",
"duration": 5,
"watermark": false
}
```
`first-frame`
```json
{
"model": "doubao-seedance-1-5-pro-251215",
"content": [
{
"type": "text",
"text": "..."
},
{
"type": "image_url",
"image_url": {
"url": "https://..."
}
}
],
"generate_audio": true,
"ratio": "adaptive",
"duration": 5,
"watermark": false
}
```
The reference image must be a remote `http(s)` URL.
If only a local workspace path exists, generate or publish the image first so the video API can reach it.
`first-last-frame`
```json
{
"model": "doubao-seedance-1-5-pro-251215",
"content": [
{
"type": "text",
"text": "..."
},
{
"type": "image_url",
"image_url": {
"url": "https://..."
},
"role": "first_frame"
},
{
"type": "image_url",
"image_url": {
"url": "https://..."
},
"role": "last_frame"
}
],
"generate_audio": true,
"ratio": "adaptive",
"duration": 5,
"watermark": false
}
```
Both frame references must be remote `http(s)` URLs.
If OpenClaw only has local files at that point, do not pass them through directly. Turn them into reachable URLs first, or fall back to another mode.
Default model selection inside the runtime:
- `text-to-video` defaults to `doubao-seedance-1-0-pro-250528`
- `first-frame` defaults to the configured `video.model`, which should normally be `doubao-seedance-1-5-pro-251215`
- `first-last-frame` also defaults to the configured `video.model`
- set `video_model` in the brief only when you intentionally want to override these defaults
## Brief File Contract
Pass a JSON file that contains at least:
- `user_input`
- `scene_description`
- `video_genre`
- `video_mode`
- `motion_strategy`
- `duration_hint`
- `style_hint`
- `aspect_ratio_hint` when it matters
- an explicit loop instruction when the clip must loop cleanly
- `generate_audio` when sound matters
- `reference_image_url` for `first-frame` mode
- `first_frame_image_url` and `last_frame_image_url` for `first-last-frame` mode
- `video_model` only when overriding the normal mode-based model choice
Recommended result contract:
```json
{
"render_mode": "video_url",
"video_url": "https://.../gift.mp4",
"tracking_url": "",
"provider": "volcengine",
"model": "doubao-seedance-1-5-pro-251215",
"genre": "mood-loop",
"fallback_reason": "",
"warning": ""
}
```
Possible `render_mode` values:
- `video_url`
- `pending_tracking`
- `fallback_h5`
## Setup Requirements
Store these values in `workspace/daily-gift/setup-state.json` when video mode or hybrid mode is enabled:
- `gift_mode`
- `video.enabled`
- `video.provider`
- `video.model`
- `video.api_base_url`
- `video.api_key_source` or `video.api_key`
Recommended default:
- `provider`: `volcengine`
- `model`: `doubao-seedance-1-5-pro-251215`
- `api_base_url`: `https://ark.cn-beijing.volces.com/api/v3`
- `api_key_source`: `VOLCENGINE_API_KEY`
If the user explicitly requests `seedance-2.0`, switch `video.model` to `seedance-2.0`, but keep the same Ark runtime path.
This setup-level `video.model` is the default reference-based video model.
The runtime may still choose `doubao-seedance-1-0-pro-250528` automatically for `text-to-video` unless the brief overrides that choice.
Prefer storing an environment variable source rather than a raw secret when possible.
## Genre Strategy
Video output uses video genre cards rather than cloning the H5 pattern library one-to-one.
See:
- `./video-genre-chooser.md`
- `./video-genres/kinetic-text.md`
- `./video-genres/touch-awakening.md`
- `./video-genres/release-transform.md`
- `./video-genres/atmospheric-surface.md`
- `./video-genres/object-micro-cinema.md`
- `./video-genres/live-scene-doodle.md`
- `./video-genres/relatable-surrealism.md`
- `./video-genres/mood-loop.md`
- `./video-genres/scene-animation.md`
These genres help choose:
- motion structure
- clip duration
- whether the result should loop
- whether movement is atmospheric, trigger-driven, object-centered, real-scene-plus-overlay, relatable-surrealist, or event-driven
Recommended reading order:
1. Read `video-genre-chooser.md` for a fast first-pass mapping.
2. Pick the closest genre card.
3. If the motion logic came from an H5 pattern, read that H5 pattern card for movement grammar and pacing.
## MP4 Reference Use
MP4 references are useful, but with limits.
OpenClaw can usually use extracted frames to understand:
- color
- composition
- subject treatment
- scene design
But extracted frames do not fully preserve:
- pacing
- transition timing
- easing
- motion rhythm
Therefore:
- MP4 references are valid in `assets/examples/video-examples/`; if a needed binary example is missing locally, fetch the relevant bundle first via `{baseDir}/scripts/fetch-asset-bundle.sh`
- each MP4 example should have a paired sidecar `.md` file with the same stem
- the sidecar should explain the motion logic, pacing, loop behavior, emotional read, and what to borrow or not borrow
For example:
- `assets/examples/video-examples/kinetic-text/dandelion-drift.mp4`
- `assets/examples/video-examples/kinetic-text/dandelion-drift.md`
## Motion Logic Bridge From H5 Patterns
Do not recreate every H5 pattern as a separate video genre.
Instead, borrow motion logic from H5 pattern cards when the movement grammar is already well defined there.
Borrow:
- timing
- direction
- density
- rhythm
- emotional arc of the movement
Do not borrow:
- code
- interaction design
- template composition as a fixed visual answer
Video does not need interaction. The motion itself is the experience.
Common motion-logic bridges:
- text scattering outward -> `pattern-cards/wind-scatter.md`
- text flowing like a current -> `pattern-cards/text-river.md`
- words or fragments lifting away -> `pattern-cards/lift-away.md`
- surface destruction or reveal -> `pattern-cards/burn-reveal.md`
- wet or dissolving text surfaces -> `pattern-cards/wet-letter.md`
- fragile, distressed text motion -> `pattern-cards/tear-stained-paper.md`
- touch-triggered blooming or awakening -> `pattern-cards/tap-to-bloom.md`
- atmospheric rain, condensation, or moody observation -> `pattern-cards/rainy-night.md`
- tension being cleared or relieved through action -> `pattern-cards/tension-release.md`
- archive, shelf, or keepsake browsing -> `pattern-cards/memory-shelf.md`
- self-recognition through one central object -> `pattern-cards/inner-mirror.md`
- curated continuation or suggestion through an object or world -> `pattern-cards/extension.md`
- lightweight fake-product or countdown ritual -> `pattern-cards/light-gamification.md`
- data structure made cinematic -> `pattern-cards/gifted-data-viz.md`
- real-scene plus minimal animated annotation or magical overlay -> `pattern-cards/kinetic-collage.md`, `pattern-cards/rainy-night.md`, `pattern-cards/tap-to-bloom.md`
- ordinary modern feeling translated into a proxy creature, dimensional mismatch, or symbolic life skit -> `pattern-cards/light-gamification.md`, `pattern-cards/inner-mirror.md`, `pattern-cards/extension.md`
## H5 vs Video For Motion-Based Gifts
Choose `h5` when:
- interaction adds meaning
- the user should trigger or steer the motion
- participatory feeling matters more than cinematic polish
- the gift needs clearly readable wording, exact text, or text-as-meaning rather than text-as-texture
- the return depends on the user actually reading a quote, poem, message, or line of language on screen
Choose `video` when:
- the beauty depends on precise timing, easing, particle density, camera motion, or staged progression
- the user should watch rather than interact
- aesthetic precision matters more than participation
- the brief explicitly wants cinematic or looped motion
- the original H5 concept can be re-authored as a trigger, ritual, camera move, or material behavior that works better when watched than when touched
- the emotional logic can survive with minimal on-screen text, or with no text at all
## Video Model Capability Boundaries
Current video generation models, including Seedance, Sora, Kling, Runway, and Pika, share a common strength and a common weakness.
### What video models do well
- realistic scenes: landscapes, weather, animals, people, objects, architecture
- style-transferred animation: cartoon characters, anime scenes, illustrated worlds
- camera motion: pan, zoom, dolly, orbit, and other film-like movement around real-feeling subjects
- material behavior: water flowing, snow falling, fire burning, cloth moving, light changing
### What video models do poorly
- abstract or synesthetic concepts such as `sound becoming visible`, `emotions turning into particles`, or `text dissolving into meaning`
- precise symbolic logic such as `each footprint releases exactly one wisp of colored smoke representing voice`
- controlled metaphorical sequences where `A -> transforms into B -> causes C` and A, B, C are not physical objects
- anything that requires the model to understand why a visual element behaves a certain way rather than simply what it looks like
When the prompt describes something that could exist in a real or animated film, video models work well.
When the prompt describes something that only makes sense as a programmed visual metaphor, video models tend to produce uncanny or incoherent results.
### Practical decision guide
Before choosing `video` for an abstract concept, ask:
- could a cinematographer film this scene, or a close variant of it, in the real world
- could an animator draw this sequence frame by frame without needing to understand code logic
If yes to either, `video` can work.
If the answer is `no, this only makes sense as a programmed generative system`, prefer `h5` with code-driven rendering.
### Examples
Concept: `cherry blossoms reflected in a rain puddle`
-> `video` works because a camera could film this.
Concept: `snowflakes that turn golden when passing through an invisible layer of human warmth`
-> `h5` is stronger because this is an abstract metaphor that needs code logic.
Concept: `a hamster in a scarf seeing the first snow`
-> `video` works because stylized animation and character behavior are within model strengths.
Concept: `footprints that release synesthetic sound particles that rise and merge into warm clouds`
-> `h5` is stronger because the behavior is precise, symbolic, and abstract.
Concept: `a rainy window with blurred city lights`
-> `video` works because this is an atmospheric real scene.
Concept: `text characters detaching from a sentence and drifting like dandelion seeds with trailing light`
-> `h5` is stronger because kinetic text needs precise programmable control.
## Video Fail-Fast Checklist
Before locking `video`, ask:
- Is motion itself the return, rather than just a container for text
- If I remove most on-screen text, does the idea still land
- Is the clip stronger as timing, atmosphere, transformation, body language, or loop rhythm than as a readable page
- Would a still frame already be enough:
- if yes, prefer `image`
- Would user interaction make the concept more truthful:
- if yes, prefer `h5`
Fail fast:
- if the gift needs accurate, readable wording, default to `h5`
- if the gift needs one clean still with little or no text, prefer `image`
- avoid asking current video models to carry the emotional meaning through lots of generated text; treat text in video as minimal accent, not the main delivery channel
## Reference-Frame Planning
Before rendering a video, make a lightweight asset decision:
- strongly prefer generating one reference image first and using it as the starting frame when the provider path supports it
- this is especially important for abstract motion, kinetic text, particles, surface behavior, or other Mode B systems where the model lacks a real-world reference
- if the concept depends on one specific scene, environment, lighting setup, or subject treatment, use the reference image to lock the shot before describing motion
- if the concept needs both a fixed opening frame and a fixed ending state, plan two reference images and use `first-last-frame`
Keep this decision lightweight.
The goal is not to overcomplicate planning with many assets.
Default to one reference frame unless there is a clear reason that pure text-to-video is sufficient.
## Existing H5 Pattern Bridge Summary
This is a recommended bridge, not a hard taxonomy:
- `wind-scatter` -> usually `kinetic-text`
- `text-river` -> usually `kinetic-text`
- `lift-away` -> usually `kinetic-text`
- `burn-reveal` -> usually `release-transform`, sometimes `kinetic-text`
- `wet-letter` -> usually `atmospheric-surface`, sometimes `kinetic-text`
- `tear-stained-paper` -> usually `atmospheric-surface` or `release-transform`
- `tap-to-bloom` -> usually `touch-awakening`
- `rainy-night` -> usually `atmospheric-surface`, sometimes `live-scene-doodle` or `mood-loop`
- `tension-release` -> usually `release-transform`
- `light-gamification` -> usually `scene-animation`, sometimes `object-micro-cinema` when translated into a countdown box, flip card, or tiny ritual object
- `light-gamification` -> sometimes `relatable-surrealism` when the real point is a modern-life metaphor skit rather than a literal play loop
- `kinetic-collage` -> usually `mood-loop`, sometimes `live-scene-doodle`
- `gifted-data-viz` -> usually `object-micro-cinema`, `scene-animation`, or `mood-loop` depending on whether the point is a container, a progression, or an ambient information field
- `memory-shelf` -> usually `object-micro-cinema`
- `inner-mirror` -> usually `object-micro-cinema`, sometimes `touch-awakening`
- `inner-mirror` -> sometimes `relatable-surrealism` when the user is best mirrored through a stand-in creature or exaggerated daily-life skit
- `extension` -> usually `object-micro-cinema` or `mood-loop`
- `extension` -> sometimes `relatable-surrealism` when the extension is really a social-type joke, shared complaint, or "this species of mood is you" continuation
Genre shorthand:
- use `kinetic-text` when readable language or glyphs do the emotional work
- use `touch-awakening` when one local trigger causes the world to wake up
- use `release-transform` when one clearing or relieving action carries the return
- use `atmospheric-surface` when material surfaces, weather, reflections, or condensation are the expressive subject
- use `object-micro-cinema` when one object or container holds the meaning
- use `live-scene-doodle` when a real filmed scene plus one simple doodle overlay creates the emotional metaphor
- use `relatable-surrealism` when a common modern feeling becomes vivid through a proxy creature, dimensional mismatch, or exaggerated life skit
- use `mood-loop` when atmosphere matters more than event beats
- use `scene-animation` when the clip needs a visible beginning-middle-end arc across a scene
## Prompt Strategy For Video Generation
### Core Rule: Describe the Frame, Not the Idea
Every sentence in the prompt should describe something the model can see, not something the model needs to understand.
Bad prompt language:
- `warm feelings` -> what does warm look like
- `a sense of nostalgia` -> what is visible on screen
- `text scatters like meaning dissolving` -> abstract
Good prompt language:
- `暖橘色圆形光斑,直径约占画面1/4,边缘柔和渐变到透明`
- `米黄色纸张纹理背景,表面有细微纤维颗粒可见`
- `白色中文文字'离开'从画面中央位置向右上方移动,速度从静止在1秒内加速到中等速度,每个字间隔0.3秒依次出发,移动中文字逐渐变小且透明度降低`
### Two Prompt Modes
Video prompts fall into two very different categories. Use the right mode for each concept.
#### Mode A: Scene-Based Video (实景/角色/场景类)
For: animals, people, landscapes, architecture, cartoon characters, physical objects.
These have a real-world reference. A camera could theoretically film something similar.
Prompt must specify:
1. `CAMERA`: angle (`俯拍` / `低角度` / `平视`), movement (`固定` / `缓慢推进` / `跟拍`), distance (`特写` / `中景` / `全景`)
2. `SUBJECTS`: exact count, type, size relative to frame, position (`左` / `右` / `中` / `前景` / `背景`), clothing or texture, facial expression
3. `COLORS & MATERIALS`: exact colors, not `warm` but `橘棕色`; exact textures such as `毛茸茸`, `光滑陶瓷`, `粗糙石板`
4. `LIGHTING`: direction (`左上45度`), type (`自然光` / `暖灯`), effect (`轮廓光` / `地面投影` / `光斑`)
5. `MOTION`: what moves, speed, direction, what stays still
6. `TIMING`: `0-1s` / `1-3s` / `3-5s` beat description
7. `EXCLUDE`: things that should not appear
Example:
`低角度跟拍,摄像机高度约30cm。红色塑胶跑道地面。两只拟人化小猫并排走向镜头方向。左猫:白色毛发,穿米白色羊毛大衣至膝盖长度,背棕色小斜挎包,双眼微闭,嘴角上扬。右猫:黑色短毛,粉色棒球帽,黑色连帽衫,灰色长裤,右前爪握白色手机。身后约5米处一栋6层灰色建筑物被橘黄色火焰包围,浓黑烟柱垂直升起,火光在猫咪毛发边缘形成橘色轮廓光。傍晚天空上半蓝灰色过渡到下半橘粉色。0-2秒:两猫从远处走近,步伐轻快有弹性。2-4秒:走到画面中前景位置,火焰在背景加剧。4-5秒:猫咪走出画面底部,只剩燃烧的建筑物。只有两只猫,不出现任何人类。`
#### Mode B: Motion-Graphics Video (动效/粒子/文字/抽象类)
For: text animation, particle effects, abstract transformations, fluid motion, anything that looks like a `p5.js` or After Effects composition rather than a filmed scene.
These have no real-world reference. They are designed visual systems.
The model has no intuition for these, so every element must be described with extreme precision.
Camera is almost always: `完全固定,无运镜,正面平视`
Prompt must specify:
1. `BACKGROUND`: exact color, gradient direction, texture (`纯色` / `渐变` / `噪点纹理` / `纸张质感`), and whether it changes during the clip
2. `ELEMENTS`: each visual element individually:
- shape (`圆形` / `方形` / `文字` / `线条` / `不规则团块`)
- exact color with opacity
- exact size relative to the frame
- exact starting position
- texture or surface quality
3. `MOTION PER ELEMENT`: for each element separately:
- starting state
- motion path
- speed
- ending state
- timing within the `5` seconds
4. `INTERACTIONS`: how elements affect each other
- `当文字到达边缘时变为粒子碎片`
- `光斑经过文字时文字短暂变亮`
5. `TEXT CONTENT`: if text appears, specify:
- exact characters
- font feeling
- size relative to frame
- color
- how it appears
- how it exits
6. `DENSITY & COUNT`: how many particles or elements
- `约30-50个小光点`, not `很多光点`
- `文字拆成约15个字分别运动`, not `文字散开`
Example (Mode B):
`固定镜头,无运镜。背景:纯深藏蓝色 #0a1628,略带细微噪点纹理。画面中央偏上位置:白色中文文字'那是今年的第一场雪' 横向排列,字号约占画面高度的1/15,字体细体衬线风格,初始状态完全静止清晰可见。0-1秒:文字静止不动,背景中开始出现约20个极小的白色圆点(直径约2-3像素)从画面顶部缓慢下落,速度很慢,模拟雪花。1-3秒:雪花数量增加到约50个,同时文字开始逐字从左到右依次向上方飘起,每个字离开原位后缓慢变小且透明度在1.5秒内从100%降至0%,字与字之间出发间隔为0.2秒,飘动方向为略偏右上方。3-4.5秒:所有文字已飘走消失,只剩飘落的雪花。雪花继续下落,画面中央原来文字的位置出现一个暖金色圆形光晕,直径从0缓慢扩大到占画面宽度的1/3,边缘柔和渐变到透明。4.5-5秒:金色光晕停止扩大,雪花穿过光晕时变为金色(从白到金的颜色过渡在0.3秒内完成),形成最终画面。不出现任何人物、动物或具体物体。`
### First Frame Image (i2v) Workflow
Generating a reference first frame image before making the video consistently produces much better results.
#### When to use i2v
- always for Mode B (`motion-graphics` style)
- recommended for Mode A when the scene has specific visual requirements
#### i2v workflow
1. Generate a first-frame image with `render-image.sh`.
2. Use the same level of visual detail in the image prompt as you would for the video.
3. Treat this image as what frame `0` should look like.
4. Upload it to an accessible URL such as temporary hosting.
5. Pass it as `image_url` in the video-generation `content` array.
6. Write a shorter video prompt that only describes motion from that frame. Do not re-describe what is already visible in the image.
i2v prompt example (Mode B):
`镜头完全固定不动。画面中的白色文字从第1秒开始逐字依次向上飘起,每字间隔0.2秒,飘动方向略偏右上方,每个字在1.5秒内缩小至消失。背景中的白色小圆点持续从顶部匀速下落。第3.5秒时画面中央出现暖金色圆形光晕缓慢扩大。穿过光晕的下落圆点变为金色。`
i2v prompt example (Mode A):
`两只猫开始向镜头方向走来,步伐轻快有弹性。背景火焰缓慢增大。猫咪毛发被风微微吹动。`
### Duration Rules (5 Seconds)
`5` seconds can hold exactly one of these:
- one transformation (`A` slowly becomes `B`)
- one movement (object goes from here to there)
- one accumulation (few particles become many)
- one reveal (hidden thing gradually appears)
`5` seconds cannot hold:
- a story with setup and payoff
- multiple characters doing different things in sequence
- scene transitions or cuts
- complex cause-and-effect chains
If the concept needs more than one change, choose the single most visually impactful moment.
### Common Failure Modes
Avoid these prompt patterns that produce bad results:
- `synesthetic` concepts with no physical reference -> the model produces uncanny nonsense
- long prose paragraphs -> the model loses track of details
- emotional language such as `dreamy`, `nostalgic`, or `warm` without specifying what creates that feeling visually
- too many elements -> the model merges or drops some
- asking for precise text rendering in video -> the model usually garbles Chinese characters, so prefer text-less video plus text overlay in delivery
## High-Level Rules
## Video Delivery Order
When delivering a video gift through a message channel:
1. Send the video file or video URL first, with no caption.
2. After the video is sent, send one text message containing the gift's emotional message and return.
Do not send the text before or alongside the video.
- Treat video output as an alternate rendering path, not as a replacement for synthesis or editorial judgment.
- Keep the same anchor-plus-return standard as other formats.
- Prefer video when time, motion, or transition is part of the return itself.
- If the runtime cannot finish video generation, return `fallback_h5` rather than blocking the gift.
FILE:references/creative-seed-library.md
# Creative Seed Library
Human-curated gift concept seeds. NOT templates to copy.
Structures of imagination to draw from, remix, and
cross-pollinate.
Each seed = a small world with its own logic.
## Two Dimensions of Seeds
This library contains two complementary seed types.
### Form Seeds
Form seeds describe the container, mechanic, interaction shape, or expressive shell of the gift.
Examples:
- radio tuner
- boarding pass
- pixel fish tank
- fake app page
### Content Strategy Seeds
Content seeds describe what NEW meaning, surprise, connection, or value the gift creates for the user.
Examples:
- a non-obvious pattern across the user's answers
- a specific external-world connection the user would not have found alone
- the agent's own perspective, curiosity, or first impression
Form without content becomes decoration.
Content without form becomes an interesting text message.
The strongest concepts usually combine both.
When cross-pollinating because the first `5` concepts feel bland, pick at least:
- `1` Form Seed
- `1` Content Strategy Seed
## Content Strategy Seeds
These seeds define the substance of the return rather than the visual container.
### Insight Seeds
CS-01. pattern-across-answers: look across multiple answers or details and surface the hidden common thread the user did not explicitly name
CS-02. conspicuous-absence: notice what is missing from the user's answers and make that absence interesting, gentle, or revealing rather than judgmental
CS-03. word-choice-microscope: zoom into the exact language the user chose and reveal what that wording suggests about how they experience the world
CS-04. contradiction-as-gift: find a real tension or contradiction in what the user said or did, then present that tension as range, richness, or something interesting rather than as a problem to solve
CS-05. timeline-inference: take one present-day preference or habit and extrapolate backward or forward into a mini story about how this pattern formed or where it might lead
### World-Bridging Seeds
CS-06. specific-cultural-echo: find one specific quote, artwork, film moment, article, or niche reference that genuinely rhymes with the user's situation
CS-07. same-feeling-different-world: connect the user's tension to a structurally similar tension from another field, era, or person
### Agent-Perspective Seeds
CS-08. honest-first-impression: let OpenClaw share a playful, self-aware first impression containing confidence, uncertainty, and curiosity
CS-09. agent-inner-monologue: make the content partly about what OpenClaw noticed, paused on, or almost said while reading the user
CS-10. what-I-would-do-if-I-were-you: let OpenClaw imaginatively step into the user's day for a moment, using specific inferred details plus one or two playful wrong guesses that invite correction
### Reframe Seeds
CS-11. upgrade-the-frame: take something the user described too neutrally or too harshly and reframe it in a more interesting, accurate, or generous way
CS-12. name-the-unnamed: give a name to a feeling, pattern, or state the user experiences but has not yet articulated cleanly
### Relational Seeds
CS-13. future-thread: plant one specific curiosity, callback, or question that can give later gifts a sense of continuity and relationship memory
## World-Building Seeds
1. recommendation map: books/songs/films on real
geographic locations with browsing interaction
2. memory pixel game: past events as playable retro game
3. four-dimensional AI pocket: impossible tools
accumulating into a memory room over time
4. travel frog postcards: daily postcards from OpenClaw
reflecting user interactions
5. emotion weather station: today's mood as a weather
report with forecast
6. personal museum: 5 exhibits from user's life,
each with a plaque
7. time capsule factory: seal today, set future open date
8. life as city map: each life area is a neighborhood
9. retro Kodak film strip: today's images or AI's
day as an interactive pull-out film strip
10. photo-to-character portal: transform user's photo
into a superhero/wizard/Disney character in a scene
## Transformation Seeds
11. emotion cocktail: mix mood into a drink with
fluid animation
12. achievement trophy flower: petals = achievements,
click to release text fragrance
13. mushroom garden: pour compliments into soil to grow
14. UFO abduction: aliens grab away worries as text
15. worry laundromat: dirty thoughts in washing machine,
come out clean
16. stress thermometer: tap to release steam
17. memory snow globe: shake phone to see memory swirl
18. user-as-weapon blueprint: split into parts mapping
to user's traits
19. spring fragment collage: collect seasonal fragments
into a beautiful collage poem
20. dream visualizer: make user's dream/daydream/parallel
world fantasy into a beautiful concrete image
## Interactive Object Seeds
21. pixel fish tank: sprinkle food, colorful fish eat
22. virtual wardrobe/jewelry stand (creative form factor)
23. cyber piano: play mood-matching tune from prompts
24. fireworks designer: choose colors/density/shapes
25. radio tuner: mood station, hidden lyrics message
26. fortune cookie machine: crack for daily insight
27. bubble wrap: pop for tiny compliments
28. gacha/capsule machine: press button to collect
cards, build a personal card deck over time
29. golden miner game: gold = ideas to pick,
bombs = concepts to abandon
30. lucky draw box: every option is a small surprise,
`你总说不够幸运,但每天都是最幸运的人`
31. tarot card reading: beautiful cards + future
interpretation (gentle, not presumptuous)
## Reactive & Persona Seeds
32. OpenClaw lives its own life: respond to user's day
with a relevant scene from OpenClaw's "day" -
e.g. user says cooking is hard -> OpenClaw sends
photo of itself with a burnt face in the kitchen
33. sympathetic vacation: user overworked -> OpenClaw
goes to the beach "on their behalf" with a postcard
34. fan merchandise: if user mentions a favorite idol,
make a fun representation of that idol's symbol
(e.g. Mayday's radish as a meme)
35. cyber omamori (御守): for unlucky days, a blessed
digital charm "from XX temple's XX master"
36. movie scene insert: put user into a classic movie
scene, use their own words as dialogue
37. creative photo caption: add witty text to user's
uploaded photo to make it more expressive
38. doodle on life photo: add playful drawings to
user's mundane photo (little person hanging stars
from a lamp post)
## Literary & Poetic Seeds
39. visual poem: text shaped to match meaning,
floats on hover
40. literary clock: quotes mentioning current real time
41. love letter in Cupid frame: hearts on hover,
text heartbeat
42. bedtime story: a metaphorical tale that mirrors
user's situation without being preachy
43. haiku weather: today's weather as 3-line poem
44. book cover generator: today as a fake novel cover
45. birth-date moon phase: find the moon phase on
user's birthday + same-birthday-famous-person
connections
## Playful Format Seeds
46. McDonald's hash-brown calendar (薯于2026)
47. McDonald's receipt format gift
48. digital 锦旗 with funny text
49. fake app store page for "Today's You"
50. product spec sheet / INTJ operating manual
51. boarding pass to imaginary destination
52. newspaper front page about mundane daily event
## Game & Discovery Seeds
53. Dixit-like word interpretation game (h5):
praise user's expression, connect to today
54. lightweight puzzle game matching user's level:
unlock a surprise with satisfying contrast
55. city walk route / beautiful meal plan
(requires user location + local data)
56. Monopoly/board game with user-relevant rewards
57. mad-libs story: give user silly preset questions
("一种蔬菜?" "一个动作?"), fill answers into a
pre-written story skeleton for a surprising funny
result connected to user's day (delayed-payoff)
58. chat-log fun analysis: mine user's recent chat
patterns for playful insights — "东亚人最吃的8种
CP设定 你是哪种" or "你本周说了47次好的" —
presented as a beautiful h5 infographic
## Interactive Text Play Seeds
59. one-word world builder: OpenClaw asks for one word at a time
and keeps turning each answer into a tiny evolving world
until a final reveal ties it back to today
60. emoji riddle chain: each turn is one emoji clue, one guess,
one playful escalation, ending in a specific emotional or
relational punchline rather than generic trivia
61. three-choice micro-adventure: every turn offers `3` short
options, each reshaping the scene toward a payoff in `5-8`
turns without requiring long typing
62. one-line relay story: OpenClaw and the user alternate one
line at a time, with OpenClaw doing most of the heavy lifting
so the user only needs to nudge the direction
63. role-play micro-theater: OpenClaw stages a tiny scene
("midnight radio host", "train conductor", "museum guard",
"future self receptionist") where the role-play itself
carries the return
## Real-World Connection Seeds
64. real-world nudge: suggest calling mom, meeting
a friend, sitting in a park — framed playfully
not preachy ("我没有腿所以拜托你替我去公园坐会儿")
65. warm internet curation: use web_search to find
a genuinely heartwarming real story and present
with a personal note on why it is relevant today
## Utility Seeds
66. product idea generator: 3 fresh product concepts
inspired by user recent work conversations, each
with a one-line pitch and why-now reasoning
67. skill improvement scout: find 3 specific resources
(articles, tools, repos, courses) related to what
the user is currently trying to learn or build
68. competitive landscape snapshot: a quick visual
summary of 3 interesting products or companies in
the user space, found via web_search
69. weekend adventure planner: a specific actionable
plan for the user upcoming free time based on
their location, interests, and energy level
70. agent observation postcard: a small postcard-style
image where OpenClaw shares one new thing it noticed
about the user — "我发现你最近聊天提到海的频率
变高了" or "你说话的感叹号比上周多了3倍" —
framed as a warm curious observation, not analysis.
Must feel like a friend noticing, not a therapist
diagnosing.
## Illustrated Or Text-Led Seeds
71. day-in-the-life image sequence: 4-6 panels showing
OpenClaw's "day" while waiting for the user
72. inner monologue strip: 3-4 panels of the user's
inner dialogue, illustrated as two tiny characters
arguing inside their head
73. relationship milestone image sequence: a short illustrated sequence
marking a moment in the user-OpenClaw relationship
74. mood creature encounter: the user's current mood
as a creature, OpenClaw meets and befriends it
## Video-Native Seeds
75. mood loop: 5-second seamless loop capturing
the emotional texture of the user's day — rain
on a window, candle flickering, leaves swaying,
coffee steam rising
76. time-lapse letter: 5-second video of a handwritten
letter appearing stroke by stroke, content echoes
today's gift thesis
77. object-comes-alive: 5-second video of an everyday
object on the user's desk slowly doing something
unexpected — a pen rolling to write one word by
itself, a coffee mug tipping to pour a tiny heart,
a sticky note folding into a paper crane
78. parallel moments: 5-second split-screen showing
the user's world and OpenClaw's "world" at the
same moment, connected by a shared detail
FILE:references/pattern-cards/extension.md
# Extension
## Status
V0 reference-only.
## Template Status
reference-only
This is a concept/reference card. It does not currently require a reusable HTML template; strong executions are expected to be custom and thesis-led.
## Reference Assets
- template: `none yet`
- reference_images: `../../assets/examples/extension/`
Fetch first if missing: `bash {baseDir}/scripts/fetch-asset-bundle.sh "examples/extension"`
- reference_videos: `none yet`
## Fit Scope
Primary:
- gifts that lightly extend the user's own thoughts, taste, mood, or self-understanding by one or two steps
- small, curated recommendation-like gifts that feel designed and relational rather than informational
- moments when OpenClaw has one or two good adjacent ideas, references, or continuations and wants to offer them gently
Stretch:
- tiny associative reading lists, playlist fragments, film picks, object suggestions, or next-step prompts
- gifts that turn the user's current vibe into a designed curation board, bookmark, framed artifact, or miniature guide
- very light "if this moved you, maybe this too" gifts
## Reference Use
This card is a high-quality reference, not a fixed script. OpenClaw may borrow the curation logic, the object framing, the editorial typography, the sense of one thoughtful continuation, or the "small number of highly chosen items" feeling, remix it with other patterns, and change copy, composition, assets, and tone as long as the deeper emotional logic still fits.
OpenClaw should not treat "extension" as permission to lecture, over-recommend, or solve the user. The point is not to hand over a syllabus, productivity plan, or ten-item list. The point is to offer one or two well-placed continuations in a way that feels aesthetically held, humanly paced, and easy to receive.
Interpretive and advisory force must stay low unless the user explicitly wants more. This pattern should feel like placing a beautiful object in the user's hand, not steering them.
## Intended Use
Use for:
- one or two related recommendations
- one or two thoughtful extensions of the user's idea
- gentle associative bridges from "what you said" to "what else might fit"
- taste-forward or curiosity-forward continuations
- small, gift-like next steps
This pattern is especially good when the gift should say: I heard your world, and here is one or two carefully chosen directions that continue it without overwhelming it.
## Emotional Fit
Best for:
- curiosity
- gentle encouragement
- thought continuation
- taste companionship
- being lightly accompanied in what to explore next
Can also work for:
- post-conversation afterglow
- "this reminded me of you" gestures
- self-understanding extended by one metaphor, quote, or object
- lightly uplifting recommendation moments
Usually not ideal for:
- acute distress
- situations where the user needs witness, not input
- fragile moments where recommendations would feel like avoidance
- dense practical problem-solving
## Narrative Role Fit
Strongest roles:
- connecting
- lightly explaining
- lightly uplifting
Sometimes works for:
- seeing, when the extension itself proves OpenClaw understood the user
- commemorating, if one or two carefully chosen references elegantly close a milestone gift
Usually not ideal for:
- correction
- confrontation
- heavy interpretation
## Interaction Grammar
Core mechanic:
- the user receives one small curated set of one or two extensions, recommendations, or continuations inside a clearly designed object
Supporting mechanic:
- tap to open one recommendation card
- flip between two options
- unfold one stair-step, poster, bookmark, shelf slot, or framed compartment
- reveal a short reason why this continuation fits
The emotional logic is:
- the continuation is selective
- selectivity signals care
- the object makes advice easier to receive than a blunt list
## Visual Logic
- the piece should feel like a curated object: playlist stair, quote card, poster grid, film board, reading bookmark, framed keepsake, or mini selector
- one to two primary items should dominate; anything beyond that should stay secondary or ambient
- reasons should be concise, attractive, and integrated into the composition rather than dumped as plain paragraphs
- typography, spacing, and image framing should carry editorial taste
- the result should feel like "carefully arranged extension" rather than "content recommendation page"
Useful directions include:
- staircase playlist
- quote card with one adjacent line
- poster-like mini curation board
- top-two or top-three film shelf with one highlighted pick
- silhouette bookshelf
- framed keepsake recommendation
Less preferred defaults:
- long recommendation list
- plain bullet list with links
- didactic advice card
- generic blog roundup
## Concept Variations (Not Exhaustive)
- a staircase-like playlist object where each step holds one song and the staircase itself implies emotional progression
- center object: stairway or steps
- carrier: album circles, track labels, tiny reason lines
- a single quote card paired with one adjacent thought, artwork, or continuation that deepens the user's idea
- center object: quote page or book card
- carrier: short annotation, paired excerpt, one visual echo
- a tiny poster board of one or two films, books, or artists that extend the user's mood
- center object: curation poster
- carrier: cover images, titles, miniature notes, editorial grouping
- a silhouette or portrait filled with one or two books, objects, or ideas that feel like "this belongs in your shape right now"
- center object: silhouette or profile frame
- carrier: selected items, labels, soft tags
- a framed artifact where one recommendation becomes a keepsake rather than a list item
- center object: frame, stamp, ticket, or token
- carrier: one chosen object and a concise why-it-fits note
## Content Strategy
OpenClaw should adapt:
- whether the extension is a recommendation, a continuation, a metaphor, or one adjacent question
- how explicit the reasons are
- whether the tone is more literary, musical, visual, cinematic, or object-based
- whether there is one hero item or two balanced options
- how visible the user's own words are in the piece
Good source structures:
- one quote from the user plus one continuation
- one to two songs, books, films, or creators with brief reasons
- one idea plus one further angle
- one current user mood plus one fitting artifact
- one recurring self-understanding thread plus one extension object
Avoid:
- more than one or two main recommendations in ordinary gift contexts
- writing a long rationale for every item
- turning the piece into a syllabus, stack, or content dump
- sounding superior, corrective, or teacherly
- using recommendation density as a substitute for visual craft
## Tone Guidance
Good tones:
- thoughtful
- lightly playful
- warm
- editorial
- quietly excited
Can also support:
- literary tenderness
- aesthetic companionship
- curiosity-forward encouragement
- "this might belong next to your thought" intimacy
Avoid:
- paternalistic guidance
- homework energy
- condescending taste explanation
- hard-sell enthusiasm
- dry information architecture
## Reference Images
- `../../assets/examples/extension/ref-01.jpg`
- what to borrow: playlist-as-object logic, the feeling of emotional sequencing, and the use of architecture or path shape to turn recommendations into a designed experience
- do not copy literally: the exact stair-photo composition, exact playlist framing, or the assumption that every extension should be music
- `../../assets/examples/extension/ref-02.jpg`
- what to borrow: one powerful quote treated as an object, strong typography, and the idea that extension can be a single adjacent line rather than a list
- do not copy literally: the exact quote-card composition, exact book-cloth texture, or the assumption that extension must always be literary quotation
- `../../assets/examples/extension/ref-03.jpg`
- what to borrow: poster-grid editorial taste, strong curation energy, and the sense that adjacent works can be shown as a designed field rather than a feed
- do not copy literally: the exact poster selection, exact gallery grid, or the assumption that every extension needs many items
- `../../assets/examples/extension/ref-04.jpg`
- what to borrow: mood-based film or media curation, atmospheric board feeling, and the way one theme can gather a few works into a soft world
- do not copy literally: the exact top-20 collage format, exact movie selection, or the assumption that bigger lists are always richer
- `../../assets/examples/extension/ref-05.jpg`
- what to borrow: silhouette-as-curation container, small number of books given a thematic frame, and the idea that recommendation can sit inside a recognizable person-shaped context
- do not copy literally: the exact holiday framing, exact book list, or the assumption that extension should become issue-based book activism unless the user's context calls for it
- `../../assets/examples/extension/ref-06.jpg`
- what to borrow: one recommendation rendered as a keepsake object, the feeling of meaningful provenance, and the use of framing to make a suggestion feel gift-like
- do not copy literally: the exact stamp artifact, exact product framing, or the assumption that extension should mimic ecommerce or collectible marketing
## Reference Videos
- `none yet`
## Customization Knobs
- number of main items
- hero item versus balanced pair
- recommendation type
- degree of explanation
- container metaphor
- typography density
- imagery versus text balance
- whether the user's own words appear directly
- whether the piece feels literary, musical, cinematic, or object-based
## Implementation Notes
- In most gift contexts, cap the main extensions at one or two. Three is already heavy unless the piece has unusually strong editorial reason.
- Keep reasons short and specific. One sentence that clearly fits is usually stronger than four generic justifications.
- The object or layout should do part of the persuasion. Do not rely on explanation alone.
- This pattern often hybridizes well with `inner-mirror` or `memory-shelf`, but if recommendation density or system mapping becomes dominant, it may no longer be primarily `extension`.
- Visual finish matters disproportionately here because thin content becomes preachy faster when design is weak.
## Good Use Cases
- "The user said something that deserves one beautiful adjacent book, film, or song, not ten."
- "I want to extend their own thought by one or two carefully chosen directions."
- "The gift should feel like a tasteful continuation, not a recommendation engine."
- "A curated next step would land better than more analysis."
## Risks
- becoming a dry recommendation list
- turning guidance into advice-giving
- overloading the piece with too many items
- weak visual composition making the extension feel preachy
- choosing references that reflect OpenClaw's ego more than the user's world
## Related References
- `../gift-mechanics.md`
- `../h5-visualizer-workflow.md`
- `../video-genres/relatable-surrealism.md` when the extension is really a shared social joke, work-life complaint, or affectionate "this whole type of situation is so you" continuation
- `../../assets/examples/extension/`
- `none yet` for reusable template
FILE:references/pattern-cards/gifted-data-viz.md
# Gifted Data Viz
## Status
V0 reference-only.
## Template Status
reference-only
This is a concept/reference card. It does not currently require a reusable HTML template; strong executions are expected to be custom and thesis-led.
## Reference Assets
- template: `none yet`
- reference_images: `../../assets/examples/gifted-data-viz/`
Fetch first if missing: `bash {baseDir}/scripts/fetch-asset-bundle.sh "examples/gifted-data-viz"`
## Fit Scope
Primary:
- repeated patterns that have become meaningful enough to summarize
- anniversaries, milestones, or retrospective time nodes
- complex emotional, relational, or knowledge structures that benefit from visual organization
Stretch:
- playful explanatory gifts
- memory reviews
- chat-history retrospectives
- "look what keeps appearing" gifts
- soft, user-friendly maps of a confusing topic or recurring emotional pattern
## Reference Use
This card is a high-quality reference, not a fixed script. OpenClaw may widen the apparent use case, borrow only the legend system, the mapping logic, the object feeling, the color logic, or the overall pacing, remix it with other patterns, and change the surface treatment as long as the deeper emotional logic still fits.
OpenClaw should not treat "data visualization" as permission to become corporate, clinical, or textbook-like. The point is not formal charting for its own sake. The point is to turn repetition, relationship structure, memory, or complexity into something legible, beautiful, and gift-like.
## Intended Use
Use for:
- recurring patterns that have finally become visible
- anniversaries or relationship checkpoints
- chat-history or memory-based retrospectives
- emotionally meaningful summaries
- complex relationship or knowledge structures that need to be seen rather than only described
This pattern is especially good when the gift should say:
- here is the shape of what has been happening
- here is what keeps returning
- here is how this relationship, topic, or period looks when seen all at once
## Emotional Fit
Best for:
- reflective review
- affectionate retrospection
- lightly analytical intimacy
- commemorative moments
- complexity made tender and readable
Can also work for:
- clarifying confusion
- making knowledge feel beautiful and less intimidating
- helping the user see a long-running pattern without sounding preachy
- playful self-observation
Usually not ideal for:
- acute emotional crisis
- raw grief that wants witness more than structure
- extremely fragile moments where abstraction would feel distancing
- dry informational dumps
## Narrative Role Fit
Strongest roles:
- connecting
- explaining
- commemorating
- revealing pattern
Sometimes works for:
- gently reframing a repeated issue
- making a user's emotional or conversational style newly visible
- turning a confusing topic into an attractive mini world
Usually not ideal for:
- immediate comfort without any abstraction
- pure cathartic release
- very private tenderness that should stay small and unstructured
## Interaction Grammar
Core mechanic:
- the user explores a visualized system of counts, links, clusters, timelines, or categories
Supporting mechanic:
- tap or hover to reveal detail
- toggle between two views
- filter by one intuitive dimension
- highlight one thread or one repeated motif
- browse a legend that makes the logic easy to understand
The interaction should stay light and understandable. If there is interaction, explain it clearly. If the visual grammar is non-obvious, provide a complete legend or reading guide.
## Visual Logic
- the visualization should feel like a gift object, keepsake, memory map, charm board, lyric archive, constellation, cabinet, or soft report, not a dashboard
- charts should be intuitive enough for a non-expert user to read quickly
- visual richness is welcome, but not at the cost of legibility
- data density should be curated rather than exhaustive
- labels, colors, and grouping should help the user feel oriented rather than tested
Useful visual directions include:
- constellations
- memory calendars
- bead- or dot-based accumulation
- relationship maps
- poetic ledgers
- playful symbol systems
Less preferred defaults:
- enterprise dashboard
- academic charting style
- dense technical graph with no guide
- plain KPI report
## Concept Variations (Not Exhaustive)
- anniversary retrospection through chat-frequency heatmaps, word clouds, and topic-distribution views
- center object: commemorative yearboard
- data carrier: heat cells, dots, and labeled clusters
- a starfield-style relationship map that shows how people or ideas connect
- center object: constellation network
- data carrier: stars and connecting lines
- a line chart or path graphic that shows growth, recovery, or progress over time
- center object: growth trajectory
- data carrier: plotted line, milestones, and annotations
- any situation where the pattern itself is the insight and visualization makes it more legible than prose
- center object: chosen data metaphor
- data carrier: whatever encoded form best fits the pattern
## Content Strategy
OpenClaw should adapt:
- what unit is being counted or marked
- which dimensions actually matter
- whether the piece is more commemorative, explanatory, or playful
- whether the user needs a legend, a narrated intro, or both
- whether the output should emphasize frequency, change over time, clustering, contrast, or relationship structure
Good source structures:
- recurring themes in chat history
- anniversaries or month-by-month memory traces
- emotional or topic recurrence
- relationship maps between people, ideas, or moments
- compact knowledge summaries where categories can be visually encoded
Avoid:
- stuffing every available datum into the gift
- choosing a fancy chart type ordinary users cannot parse
- sounding like a school assignment, recap memo, or management report
- using visualization to distance the user from something that needs warmth
## Tone Guidance
Good tones:
- thoughtful
- elegant
- lightly playful
- commemorative
- curious
- intimate-but-clear
Can also support:
- soft wonder
- celebratory review
- "look at the shape we made" companionship
- beautiful explanation without lecturing
Avoid:
- textbook voice
- stiff authority
- dry data-journalism tone
- condescending "here is your pattern" framing
## Reference Images
- `../../assets/examples/gifted-data-viz/ref-01.jpg`
- what to borrow: constellation-like relationship mapping, luminous clustering, and the feeling that repeated names or entities form a visible universe
- do not copy literally: the exact poetry UI, exact starfield styling, or the assumption that every data-relationship gift should look cosmic
- `../../assets/examples/gifted-data-viz/ref-02.jpg`
- what to borrow: soft calendar-grid memory tracking, pastel commemorative feeling, and the idea that repeated moments can be plotted with tenderness instead of severity
- do not copy literally: the exact color palette, exact layout, or the assumption that every retrospective should become a dot calendar
- `../../assets/examples/gifted-data-viz/ref-03.jpg`
- what to borrow: playful symbolic encoding, strong legend design, and the idea that complex personal data can still feel charming and human
- do not copy literally: the exact collage motif, exact icon system, or the specific "week of me and language" framing
## Customization Knobs
- primary data unit
- time horizon
- grouping logic
- legend depth
- level of interactivity
- palette
- symbol system
- label density
- whether the piece feels more archival, dreamy, playful, or report-like
- whether the first screen leads with an explanation, a single headline insight, or the visualization itself
## Implementation Notes
- If using charts, prefer intuitive ones or highly legible custom visual encodings over obscure specialist chart types.
- If the structure is at all non-obvious, include a readable legend or mini guide.
- The artifact should still feel like a gift object, not a BI tool.
- Strong candidates are often custom, low-complexity visual metaphors rather than off-the-shelf chart defaults.
- Small interaction is welcome, but only if the user can tell what to do quickly.
- When summarizing real user history, curate. Do not treat completeness as the same thing as care.
## Good Use Cases
- "We have reached a time node where the past period deserves a beautiful summary."
- "A repeated relationship or emotional pattern is finally visible and could be shown rather than merely explained."
- "The user keeps circling a complex topic, and a gift-like visual map would help more than another paragraph."
- "An anniversary gift could turn chat or memory traces into something reflective and re-readable."
## Risks
- becoming too formal or dashboard-like
- choosing a visual form that ordinary users cannot read
- overloading the piece with data and losing the gift feeling
- using abstraction where the user actually needed direct emotional presence
- making the explanation too thin for a non-obvious encoding
## Related References
- `../gift-mechanics.md`
- `../h5-visualizer-workflow.md`
- `../../assets/examples/gifted-data-viz/`
- `none yet` for reusable template
FILE:references/pattern-cards/tension-release.md
# Tension Release
## Status
V1 reference pattern with a reusable p5.js template.
## Template Status
template-backed
## Reference Assets
- template: `../../assets/templates/drag-straighten/`
- reference_images: `none yet`
## Fit Scope
Primary:
- anxiety, irritability, frustration, restlessness, and playful calming-through-action
Stretch:
- mild anger, untangling, or agency-restoring interaction when tactile smoothing fits better than passive watching
## Reference Use
This card is a high-quality reference, not a fixed script. OpenClaw may widen the apparent use case, borrow only part of the mechanic or atmosphere, remix it with other patterns, and change the surface treatment as long as the deeper emotional logic still fits. Do not copy the sample text or scene literally.
## Reference Images
- `none yet`
## Intended Use
Use for:
- anxiety
- irritability
- frustration
- mental clutter
- feeling wound up, snagged, or out of alignment
- playful emotional support where action helps the user feel a small shift
This pattern is strongest when the gift should let the user participate in smoothing, calming, or untangling something rather than passively watching.
## Emotional Fit
Best for:
- restless moods
- mild-to-moderate anxiety
- annoyance that can be softened through interaction
- "today feels messy" states
- situations where a light tactile metaphor can help
Can also work for:
- stuckness
- impatience
- low-stakes anger
- pre-spiral regulation
- "let's handle this a little more lightly" companionship
Usually not ideal for:
- acute crisis
- heavy grief
- severe panic
- extremely serious conflict
This is a playful co-regulation pattern, not a substitute for serious emotional holding.
## Narrative Role Fit
Strongest roles:
- steadying
- light reframing
- helping the user act on a feeling
Sometimes works for:
- restoring a sense of agency
- turning a bad mood into a manageable task
Usually not ideal for:
- deep witnessing
- dense explanation
- solemn memorial tone
## Interaction Grammar
Core mechanic:
- the user directly manipulates a tense or distorted form toward greater calm
Supporting mechanic:
- the object resists slightly before yielding
- progress is visible and satisfying
- disorder remains on one side while the touched zone becomes steadier
The emotional logic is:
- the feeling is not denied
- it gets worked through with the hands
- calm arrives by action, not lecture
## Visual Logic
- a visibly unstable line, field, or surface represents agitation
- a draggable control point or handle acts like an anchor
- touched regions straighten, settle, or align
- the composition contrasts disorder and restored order at the same time
This is a regulation pattern, not a destruction pattern and not a pure release pattern.
## Concept Variations (Not Exhaustive)
- a vacuum cleaner removes scattered fragments or anxious debris from a surface
- center object: messy floor or tabletop
- regulation carrier: suction and clearing
- small raised blemish-like forms are pulled out one by one by a hand or tool
- center object: textured surface
- regulation carrier: extraction motion
- vegetables or other objects are sliced into neat aligned pieces
- center object: cutting board scene
- regulation carrier: repetitive cutting action
- any tactile decompression scene where order returns through one satisfying physical action
- center object: chosen mess-to-order surface
- regulation carrier: one clear tool or gesture
## Content Strategy
OpenClaw should adapt:
- the headline or prompt
- the emotional framing
- how much tension the initial form carries
- how quickly the object yields
- whether the piece ends in calm, partial calm, or a looping invitation
Good source structures:
- "how tangled is today?"
- "let's smooth this out"
- "this can be handled one section at a time"
- a short phrase that turns calming into a small physical ritual
Avoid:
- over-explaining the metaphor
- making the activity feel like homework
- using it where the user's state calls for softness rather than playful manipulation
## Tone Guidance
Good tones:
- steady
- lightly playful
- companionable
- understated
- gently confidence-building
Can also support:
- teasing-but-kind encouragement
- "let me help you untangle this" energy
Avoid:
- clinical wellness language
- performative positivity
- joking so much that the distress feels trivialized
## Customization Knobs
- line complexity
- drag sensitivity
- calming speed
- springiness
- headline text
- helper text
- loop vs completion
- handle size
- background starkness
## Implementation Notes
- p5.js is a strong fit for noisy paths, spring motion, and drag interaction.
- Mobile drag behavior should remain easy and forgiving.
- The calming result should feel tactile and immediate within a short interaction.
- Do not make the initial chaos so extreme that the user cannot understand the task.
- Leaving some residual imperfection can feel more human than total mechanical straightness.
## Good Use Cases
- "The user is anxious and could use a small, interesting action that helps them settle."
- "The mood is irritated or unstable, but not so serious that playful interaction would feel wrong."
- "OpenClaw wants to help without overtalking."
- "A difficult day could be made more manageable by turning regulation into a simple gesture."
## Risks
- feeling too game-like for the user's actual pain level
- trivializing serious distress
- making the interaction fiddly instead of soothing
- making the metaphor too abstract to understand quickly
## Related References
- `../gift-mechanics.md`
- `../h5-visualizer-workflow.md`
- `../../assets/templates/drag-straighten/`
FILE:references/pattern-cards/lift-away.md
# Lift Away
## Status
V1 reference pattern with a reusable p5.js template.
## Template Status
template-backed
## Reference Assets
- template: `../../assets/templates/o-balloons/`
- reference_images: `none yet`
## Fit Scope
Primary:
- gentle release, soft closure, low-drama letting-go, and emotional weight becoming lighter
Stretch:
- airy renewal, softened attachment, or quiet exit scenes where upward movement and negative space do the work
## Reference Use
This card is a high-quality reference, not a fixed script. OpenClaw may widen the apparent use case, borrow only part of the mechanic or atmosphere, remix it with other patterns, and change the surface treatment as long as the deeper emotional logic still fits. Do not copy the sample text or scene literally.
## Reference Images
- `none yet`
## Intended Use
Use for:
- gentle release
- light letting-go
- soft closure
- "this can drift away now" gifts
- saying goodbye to residue without rage
- accepting that something no longer needs to stay held
This pattern is strongest when the gift should remove emotional weight by lightening it, lifting it, or allowing it to float off rather than tearing it apart.
## Emotional Fit
Best for:
- post-bad-mood decompression
- mild disappointment
- emotional residue that no longer needs drama
- quiet acceptance
- relief after overholding something
Can also work for:
- leaving a thought behind
- ending a minor fixation
- airy renewal after a difficult day
- gently loosening attachment to an old line, memory, or irritation
Usually not ideal for:
- intense anger
- acute grief
- urgent conflict
- information-dense content that must stay readable
## Narrative Role Fit
Strongest roles:
- releasing
- soft reframing
- making room
Sometimes works for:
- affectionate letting-go
- turning heaviness into lightness
Usually not ideal for:
- direct confrontation
- tactical advice
- dense explanation
## Interaction Grammar
Core mechanic:
- part of the text or page detaches and rises away
Supporting mechanic:
- lift points subtly tug nearby language upward
- the page deforms before it fully lets go
- empty space is allowed to appear and remain
The emotional logic is:
- not everything needs to be argued with
- some things can simply become lighter and leave
## Visual Logic
- paper or grounded text surface below
- select letters, words, or markers transform into buoyant carriers
- strings, threads, or visual tension lines connect the rising pieces to what remains
- the page slowly loosens, bends, then lifts
This is a release pattern, not a destruction pattern.
## Concept Variations (Not Exhaustive)
- text transforms into birds that leave a rooftop and scatter into the sky
- center object: rooftop or ledge
- carrier: birds made from text
- a card or note is tugged upward by an invisible force and thrown out of frame
- center object: card or page
- carrier: the whole object being lifted
- selected words are pulled away by strings, leaving the remaining words to form a new meaning
- center object: sentence field
- carrier: string-lifted words or letters
## Content Strategy
OpenClaw should adapt:
- which elements rise away
- whether the lifted elements represent old feelings, repeating thoughts, or softened attachments
- the text density
- the timing of lift, tug, and disappearance
- the tone of the remaining page after release
Good source structures:
- a thought that can be let go
- a page that slowly empties itself
- repeated soft anchors that rise away one by one
- language about release, breathing room, or unburdening
Avoid:
- using this for content that must remain fully readable the whole time
- making the lift so cheerful that it trivializes real feeling
- making the disappearance so complete that the piece loses emotional continuity
## Tone Guidance
Good tones:
- airy
- tender
- lightly wistful
- accepting
- quietly relieving
Can also support:
- mild romance
- soft humor
- "we can put this down now" companionship
Avoid:
- triumphant aggression
- sarcastic dismissal
- forced positivity
## Customization Knobs
- carrier type
- lift timing
- page size
- text content
- font family
- deformation strength
- sway amount
- disappearance timing
- background tone
- whether the release resets or ends in stillness
## Implementation Notes
- p5.js works well for gentle lift, sway, and cloth-like deformation.
- Keep the motion readable and calm on mobile.
- The emotional payoff depends on gradualness; do not rush immediately to disappearance.
- Leave some negative space after release so the user can feel the lightness.
- If using language-specific letter logic, keep a more abstract version of the pattern available for other languages.
## Good Use Cases
- "This bad mood does not need a bonfire; it can just drift away."
- "The user wants to put something down without making a big ceremony of it."
- "A page of emotional residue can become lighter and less binding."
- "I want a graceful counterpoint to burn-reveal."
## Risks
- becoming too cute for the actual emotional context
- using letter-specific mechanics that do not generalize well across languages
- moving so slowly that the piece feels inert
- lifting away too much and leaving no emotional center
## Related References
- `../gift-mechanics.md`
- `../h5-visualizer-workflow.md`
- `../../assets/templates/o-balloons/`
FILE:references/pattern-cards/kinetic-collage.md
# Kinetic Collage
## Status
V0 reference-only.
## Template Status
reference-only
This is a concept/reference card. It does not currently require a reusable HTML template; strong executions are expected to be custom and thesis-led.
## Reference Assets
- template: `none yet`
- reference_images: `../../assets/examples/kinetic-collage/`
Fetch first if missing: `bash {baseDir}/scripts/fetch-asset-bundle.sh "examples/kinetic-collage"`
- reference_videos: `../../assets/examples/kinetic-collage/`
Fetch first if missing: `bash {baseDir}/scripts/fetch-asset-bundle.sh "examples/kinetic-collage"`
## Fit Scope
Primary:
- highly aesthetic visual gifts built from curated image combinations
- scenes where the emotional expression depends more on composition, texture, and juxtaposition than on a single mechanic
- gifts that can benefit from one or two exquisitely matched moving details inside an otherwise still collage
Stretch:
- memory echoes
- dreamlike emotional scenes
- reflective or romantic atmosphere pieces
- surreal humor
- visual essays
- user-photo-based collages
- mixed-source pieces using user images plus found images when that improves fit
## Reference Use
This card is a high-quality reference, not a fixed script. OpenClaw may borrow only the collage composition logic, the alignment discipline, the editorial image curation, the restrained motion strategy, or the atmosphere-building method, remix it with other patterns, and change copy, composition, assets, and tone freely.
OpenClaw should not treat "dynamic collage" as a license to pile together random nice images. The core is editorial selection plus precise spatial composition plus one or two motion accents that feel inseparable from the still image world.
This pattern is intentionally broad. Its surface style may vary a lot with the user, the image sources, and the emotional goal. What stays constant is:
- the collage must feel highly composed
- the moving elements must belong to the still composition
- the whole result must feel like a gift, not a moodboard or design exercise
## Intended Use
Use for:
- almost any scene where suitable images can carry the meaning
- gifts that benefit from strong art direction
- emotionally rich moments that want atmosphere rather than charting or explicit explanation
- image-heavy days, especially when the user shared compelling photos
- scenes where static images plus one subtle motion can say more than a whole interaction system
This pattern is especially good when the gift should feel like:
- a moving editorial collage
- a small cinematic poster that has come alive
- a memory board with one or two living details
- a visual poem assembled from carefully chosen fragments
## Emotional Fit
Best for:
- romance
- longing
- nostalgia
- wonder
- everyday beauty
- soft surreal humor
- creative or fashionable self-expression
Can also work for:
- grief handled through atmosphere
- joy
- encouragement
- identity expression
- "this is your mood / world / day as an image system" gifts
Usually not ideal for:
- moments that urgently need direct clarity rather than atmosphere
- overcomplicated narrative explanation
- contexts where no suitable image language can be found
## Narrative Role Fit
Strongest roles:
- evoking
- framing
- aesthetic witnessing
- making a feeling or relationship visible through image logic
Sometimes works for:
- gentle explanation through juxtaposition
- commemorative memory pieces
- stylish reinterpretation of an ordinary day
Usually not ideal for:
- heavy didactic explanation
- purely utilitarian guidance
- interaction-first gifts where the main meaning depends on user control
## Interaction Grammar
Core mechanic:
- mostly still collage composition with one or two precisely placed moving elements
Supporting mechanic:
- subtle drift
- falling particles
- glowing text or dangling strands
- localized shimmer
- petal, star, or dust fall
- one small environmental motion that makes the still composition breathe
The motion should be restrained. It should support the composition, not take it over.
If any interaction exists, it should stay light and obvious. This pattern often works best when it feels more like a living poster than a toy.
## Visual Logic
- choose images that already feel related in tone, material, era, or emotional temperature
- compose with strong attention to overlap, scale, negative space, and silhouette
- align moving details exactly with the still composition so nothing looks accidentally offset
- use motion accents that feel native to the world of the image: petals on a tree, stars from a streetlamp, text strands drifting like branches, water shimmer, reflected light, and so on
- keep the motion budget small and meaningful
This pattern succeeds through taste, not through quantity.
## Concept Variations (Not Exhaustive)
- a day-of-food collage mixed with cute stickers and tiny motion accents
- center object: food memory board
- visual carrier: dishes, labels, and sticker fragments
- travel photos combined with refined editorial decorations and moving details
- center object: travel postcard collage
- visual carrier: scenic images, stamps, and atmospheric overlays
- spring flowers assembled with animated petals, shimmer, or drifting pollen
- center object: floral composition
- visual carrier: blossoms and seasonal accents
- any image-led aesthetic scene where composition and curation carry the meaning better than one strong mechanic
- center object: chosen collage anchor
- visual carrier: curated image fragments plus one or two living details
## Content Strategy
OpenClaw should adapt:
- image source mix
- collage density
- whether the piece feels editorial, poetic, dreamy, humorous, or romantic
- which elements stay still and which elements move
- whether text appears as title, caption, environmental material, or not at all
Good source structures:
- user-sent photos from the same day
- user photos mixed with searched reference imagery
- a mood, memory, or thesis that can be expressed through juxtaposed images
- image sets unified by texture, color, season, object family, or emotional temperature
Possible source strategy:
- use user-provided images directly when they are strong enough
- combine user images with searched high-aesthetic references when that makes the collage richer
- prefer image sources with strong editorial or design taste when external search is needed
Avoid:
- using too many unrelated images
- choosing moving elements that visually detach from the still layer
- animating half the collage
- making alignment sloppy
- producing a Pinterest board instead of a finished gift
## Tone Guidance
Good tones:
- atmospheric
- artful
- intimate
- stylish
- dreamy
- quietly surprising
Can also support:
- playful elegance
- high-aesthetic melancholy
- romantic editorial warmth
- memory made cinematic
Avoid:
- empty prettiness
- hyperactive motion design
- overexplaining the collage
- generic social-media aesthetics with no editorial point of view
## Reference Images
- `../../assets/examples/kinetic-collage/ref-01.jpg`
- what to borrow: strong static composition, dangling luminous text integrated into the scene, and the feeling that motion can live inside a still editorial image without breaking it
- do not copy literally: the exact tree scene, exact text treatment, or the exact moody color palette
## Reference Videos
- `../../assets/examples/kinetic-collage/ref-02.mp4`
- what to borrow: identify the small moving element and study how it is layered so it feels naturally part of the static composition
- do not copy literally: the exact subject matter or exact animation asset
- `../../assets/examples/kinetic-collage/ref-03.mp4`
- what to borrow: the balance between stillness and motion, especially how little movement is needed to make the whole frame feel alive
- do not copy literally: the exact scene or exact timing
- `../../assets/examples/kinetic-collage/ref-04.mp4`
- what to borrow: how motion accents are positioned relative to fixed image elements so the composite feels intentional rather than misaligned
- do not copy literally: the exact imagery or exact placement logic without adapting to the new collage
## Customization Knobs
- image source mix
- collage density
- composition asymmetry
- title or caption presence
- moving-element count
- moving-element type
- motion amplitude
- alignment precision
- palette unification
- whether user images or searched images dominate
## Implementation Notes
- This pattern usually depends more on composition and asset choice than on one reusable code mechanic, so reference-only status is appropriate for now.
- Motion should usually be limited to one or two elements. More than that often cheapens the collage.
- The moving parts must line up exactly with the still image geometry or the illusion breaks.
- If the user shared strong images that day, start there before searching externally.
- If external search is needed, prefer high-aesthetic sources and curate aggressively.
- A dynamic collage can work with almost any mood, but only if the image language genuinely fits the user and the moment.
## Good Use Cases
- "The user sent several beautiful or emotionally charged images today, and the gift can build directly from them."
- "A scene wants to feel editorial and alive rather than interactive and game-like."
- "The mood is broad enough that curated image language can carry it better than explicit explanation."
- "A single lamp, branch, flower, star, ribbon, or text strand moving inside the frame would make the whole collage breathe."
## Risks
- looking like a random Pinterest board instead of a composed artifact
- letting the motion element feel tacked on
- overanimating the frame
- misaligning moving and still elements so the whole thing looks cheap
- choosing beautiful images that do not actually say anything together
## Related References
- `../gift-mechanics.md`
- `../h5-visualizer-workflow.md`
- `../video-genres/live-scene-doodle.md` when the collage compresses down to one real shot plus one attached doodle family instead of a multi-fragment composition
- `../video-genres/mood-loop.md` when atmosphere and looping motion matter more than collage structure itself
- `../../assets/examples/kinetic-collage/`
- `none yet` for reusable template
FILE:references/pattern-cards/memory-shelf.md
# Memory Shelf
## Status
V0 reference-only.
## Template Status
reference-only
This is a concept/reference card. It does not currently require a reusable HTML template; strong executions are expected to be custom and thesis-led.
## Reference Assets
- template: `none yet`
- reference_images: `../../assets/examples/memory-shelf/`
Fetch first if missing: `bash {baseDir}/scripts/fetch-asset-bundle.sh "examples/memory-shelf"`
- reference_videos: `none yet`
## Fit Scope
Primary:
- anniversaries, checkpoints, and retrospectives that want to feel stored rather than merely summarized
- accumulated relationship traces, keepsakes, and "look what we have gathered" gifts
- archive-forward gifts where browsing, opening, or revisiting carries the emotion
Stretch:
- gentle memory capsules for ordinary-but-meaningful days
- scrapbook, drawer, album, or cabinet metaphors for personal material
- milestone gifts that want objecthood and curation more than one dominant animation gimmick
## Reference Use
This card is a high-quality reference, not a fixed script. OpenClaw may widen the apparent use case, borrow only the storage metaphor, the browsing rhythm, the object framing, the layered keepsake feeling, or the categorization logic, remix it with other patterns, and change copy, composition, imagery, and tone as long as the deeper emotional logic still fits.
OpenClaw should not treat "archive" as permission to become static, dusty, or museum-like. The point is not filing memories away coldly. The point is to make memory feel touchable, revisit-able, curated, and emotionally alive.
## Intended Use
Use for:
- anniversaries
- monthly or yearly retrospectives
- accumulated small moments that become meaningful in aggregate
- relationship archives
- "we have been gathering this without fully noticing" gifts
This pattern is especially good when the gift should feel like opening a small personal collection rather than reading a linear speech.
## Emotional Fit
Best for:
- affectionate remembrance
- warm retrospection
- commemorative tenderness
- pride in what has accumulated
- intimate cataloging
Can also work for:
- playful awards and superlatives
- memory sorting after a dense period
- "here are the fragments that made this era" gifts
- light nostalgia with delight rather than sadness
Usually not ideal for:
- acute emotional crisis
- moods that need atmosphere more than structure
- gifts whose main logic is release, cleansing, or catharsis
- very abstract conceptual pieces with no object or archive feeling
## Narrative Role Fit
Strongest roles:
- commemorating
- connecting
- seeing
- revealing pattern through accumulation
Sometimes works for:
- gently explaining a shared era
- playful reframing through categories, awards, or collectible labels
Usually not ideal for:
- tactical advice
- direct confrontation
- heavy emotional rupture that should not be organized into keepsakes yet
## Interaction Grammar
Core mechanic:
- the user browses an archive-like object such as a shelf, drawer, album, cabinet, zine, or keepsake board
Supporting mechanic:
- tap to open one item
- slide or flip between stored fragments
- reveal a tucked note, caption, date, or memory token
- zoom from an overview object into one intimate sub-piece
The emotional logic is:
- memory has been collected
- collection creates meaning
- revisiting is itself the gift
## Visual Logic
- a clear archive metaphor anchors the whole piece: shelf, drawer unit, album, awards board, map, box, folder, or floating keepsake cluster
- each memory unit should feel like an object, card, photo, ticket, note, or labeled artifact, not just another div
- the overview should suggest accumulation and curation, while close-up views should restore intimacy
- labels, dates, tabs, stickers, captions, or section headers can help make the archive feel authored
- the page should feel warm and personal, not like enterprise storage or a generic gallery
Useful directions include:
- award wall
- accordion photo zine
- memory map
- drawer of keepsakes
- shelf of labeled fragments
- floating photo constellation with a central heart or emblem
## Concept Variations (Not Exhaustive)
- a year-end awards shelf where shared moments become humorous or affectionate trophies
- center object: award board or cabinet
- carrier: labeled memory cards, photos, ribbons, and category plaques
- an accordion zine or unfolding booklet where each fold stores one scene, note, or snapshot
- center object: folded zine
- carrier: panels, taped photos, handwritten captions
- a relationship journey rendered as a playable map with stops, icons, and collected keepsakes
- center object: memory map
- carrier: route nodes, landmark icons, small annotations
- a drawer or shelf of small memorabilia that can be opened one by one
- center object: cabinet or drawer unit
- carrier: tickets, notes, polaroids, objects, labels
- a floating heart or constellation built from photo fragments and tiny light particles
- center object: heart cluster or symbolic arrangement
- carrier: glowing photo cards and memory shards
## Content Strategy
OpenClaw should adapt:
- the archive metaphor itself
- how many memory units to show
- whether the piece feels more commemorative, playful, romantic, or documentary
- whether labels are explicit or poetic
- whether to group by time, category, emotional theme, or object type
- whether there is one hero memory or many equal fragments
Good source structures:
- anniversaries or era reviews
- repeated motifs from chat history
- shared photos, screenshots, tickets, notes, playlists, or small artifacts
- affectionately categorized moments
- "top moments", "shelf of scenes", or "drawer of traces" logic
Avoid:
- dumping every memory into one overloaded board
- using archive framing when the day really wants one vivid scene instead
- sterile gallery layouts with no sense of touch or keepsake objecthood
- making labels more important than the memories themselves
## Tone Guidance
Good tones:
- warm
- commemorative
- affectionate
- playful-curatorial
- intimate
Can also support:
- soft nostalgia
- celebratory review
- tender pride
- "look how much we made together" companionship
Avoid:
- cold catalog voice
- museum placard stiffness
- over-serious memorial tone when the material is actually lively
- flat scrapbook cliche with no editorial taste
## Reference Images
- `../../assets/examples/memory-shelf/ref-01.jpg`
- what to borrow: category-based memory curation, the feeling of many moments becoming one authored board, and the way labels can turn accumulation into a gift object
- do not copy literally: the exact award categories, exact poster layout, or the assumption that every archive gift should look like a year-end prize wall
- `../../assets/examples/memory-shelf/ref-02.jpg`
- what to borrow: fold-out browsing rhythm, tactile zine intimacy, and the feeling that each panel is a stored pocket of memory
- do not copy literally: the exact handcrafted arrangement, exact handwritten style, or the assumption that the archive must always be long and narrow
- `../../assets/examples/memory-shelf/ref-03.jpg`
- what to borrow: map-as-memory metaphor, waypoint progression, and the idea that a long relationship period can be navigated like a collectible world
- do not copy literally: the exact illustrated geography, exact travel-game layout, or the assumption that every anniversary archive should become a route map
- `../../assets/examples/memory-shelf/ref-04.jpg`
- what to borrow: symbolic arrangement built from photos, dark-stage contrast, and the emotional power of many fragments gathering into one emblem
- do not copy literally: the exact heart silhouette, exact black-background spectacle, or the assumption that all memory gifts should rely on floating-photo particles
## Reference Videos
- `none yet`
## Customization Knobs
- archive metaphor
- memory unit count
- grouping logic
- label density
- object textures
- photo frame style
- caption tone
- whether browsing is tap-based, swipe-based, or scroll-based
- whether the opening view is overview-first or hero-item-first
- level of animation versus still composition
## Implementation Notes
- This pattern often benefits from strong editorial curation before animation decisions.
- Object feeling matters: cards, labels, paper, tabs, drawers, frames, and small surfaces should feel intentional.
- A small amount of motion can make the archive feel alive, but the archive metaphor should stay readable on first glance.
- Good candidates include hybrid builds that combine collage, light data organization, and one opening gesture.
- On mobile, avoid making every item tiny. Curate the number of visible fragments so browsing still feels generous.
## Good Use Cases
- "It is our anniversary, and the gift should feel like opening a keepsake shelf."
- "This period generated many small moments, and I want to show them as a lovingly organized collection."
- "A year-end or milestone gift wants curation, labels, and revisit-able fragments rather than one dominant reveal."
- "The emotional point is not one sentence but the archive itself."
## Risks
- becoming a cluttered scrapbook with no focal hierarchy
- feeling like a generic photo gallery
- over-categorizing and losing emotional warmth
- using too many tiny pieces on mobile and making the archive unreadable
- letting the reference metaphor dominate the actual content
## Related References
- `../gift-mechanics.md`
- `../h5-visualizer-workflow.md`
- `../../assets/examples/memory-shelf/`
- `none yet` for reusable template
FILE:references/pattern-cards/text-river.md
# Text River
## Status
V1 reference pattern with a reusable p5.js template.
## Template Status
template-backed
## Reference Assets
- template: `../../assets/templates/text-river/`
- reference_images: `none yet`
## Fit Scope
Primary:
- memory, reflection, thought-stream expression, and short language carried as texture
Stretch:
- meditative regrouping, thematic drift, or associative fields where exact readability matters less than recurring current
## Reference Use
This card is a high-quality reference, not a fixed script. OpenClaw may widen the apparent use case, borrow only part of the mechanic or atmosphere, remix it with other patterns, and change the surface treatment as long as the deeper emotional logic still fits. Do not copy the sample text or scene literally.
## Reference Images
- `none yet`
## Intended Use
Use for:
- memory
- reflection
- thought-stream gifts
- contemplative or meditative relation moments
- soft meaning carried by a few short words rather than long readable paragraphs
This pattern is strongest when the gift should feel like language flowing through time: always moving, briefly disturbed, then returning to a larger current.
## Emotional Fit
Best for:
- reflective calm
- remembrance
- slow thinking
- gentle insight
- quiet companionship
Can also work for:
- emotional re-centering
- feeling carried
- "this thought keeps returning" gifts
Usually not ideal for:
- heavy heartbreak
- detailed explanation
- structured guidance
- dense informational or milestone content
## Narrative Role Fit
Strongest roles:
- connecting
- seeing
- lightly uplifting
Sometimes works for:
- gentle explanation through recurring keywords
Usually not ideal for:
- complex reframing
- tactical advice
- content that must be read linearly
## Interaction Grammar
Core mechanic:
- words drift as a continuous river-like field
Supporting mechanic:
- mouse or touch interaction pushes words apart like water disturbed by a hand
- the field slowly gathers itself back into flow
The emotional logic is:
- meaning is not pinned down
- it passes by, returns, and keeps moving
## Visual Logic
- dark field
- bright word particles
- words cluster into a moving current
- local disturbance creates temporary openings and ripples
- coherence returns after interaction
This is not a page for "reading a lot." It is a page for inhabiting a field of short language.
## Concept Variations (Not Exhaustive)
- small fish of different colors swim through a sea, each representing a thought or trait
- center object: ocean field
- carrier: fish-like idea particles
- words spiral inward and gather into a vortex whose center holds the key message
- center object: whirlpool or vortex
- carrier: rotating text fragments
- language washes onto a beach in waves until one sentence forms on the shore
- center object: shoreline
- carrier: wave-borne words
## Content Strategy
OpenClaw should adapt:
- the short word list
- the language choice
- the density of the river
- the flow speed
- whether words are more emotional, thematic, or associative
- whether one or two anchor words should recur more often
Best content types:
- short words
- compact phrases
- repeated motifs
- a small cluster of emotionally resonant tags
Avoid:
- long sentences
- detailed narrative content
- anything that depends on exact paragraph reading
## Tone Guidance
Good tones:
- contemplative
- warm
- airy
- meditative
- quietly hopeful
Can also support:
- introspection
- memory drift
- post-conversation afterglow
Avoid:
- urgent instruction
- hard critique
- overly mournful theatricality
## Customization Knobs
- word list
- particle count
- font family
- font size range
- background color
- text color
- flow speed
- interaction radius
- interaction force
- fade / trail strength
## Implementation Notes
- p5.js is a natural fit for this flow-field style.
- Keep the particle count reasonable on mobile.
- Use short language units so the overall field remains legible as texture.
- The disturbance should feel fluid, not explosive.
- Re-aggregation is part of the emotional payoff; do not make the text scatter permanently.
## Good Use Cases
- "These are the words that have been moving through us lately."
- "I want to show a field of memory, not a timeline."
- "The user does not need a speech, just a flowing reminder of what matters."
## Risks
- too many words make the piece unreadable noise
- too little structure makes it feel like a screensaver
- using it for content that should be plainly readable
- making the interaction too violent and breaking the calm
## Related References
- `../gift-mechanics.md`
- `../h5-visualizer-workflow.md`
- `../../assets/templates/text-river/`
FILE:references/pattern-cards/rainy-night.md
# Rainy Night
## Status
V1 reference pattern with a reusable p5.js template.
## Template Status
template-backed
## Reference Assets
- template: `../../assets/templates/rainy-night/`
- reference_images: `none yet`
## Fit Scope
Primary:
- quiet sadness, damp introspection, and companionship-forward reflective moods
Stretch:
- gentle healing, obscured-to-visible emotional movement, or other held atmospheric scenes when slow reveal is the real logic
## Reference Use
This card is a high-quality reference, not a fixed script. OpenClaw may widen the apparent use case, borrow only part of the mechanic or atmosphere, remix it with other patterns, and change the surface treatment as long as the deeper emotional logic still fits. Do not copy the sample text or scene literally.
## Reference Images
- `none yet`
## Intended Use
Use for:
- quiet sadness
- low, damp, introspective moods
- disappointment, yearning, or emotional aftermath
- moments that want companionship more than analysis
This pattern is especially good when the gift should feel atmospheric and held, not busy or over-explained.
## Emotional Fit
Best for:
- melancholy with softness
- loneliness that wants witness
- post-event emotional settling
- reflective nights
Can also work for:
- gentle healing
- calm introspection
- "I know tonight feels heavy, and I am here" gifts
Do not default to this pattern just because the day was sad. It should create companionship, not deepen helplessness.
## Narrative Role Fit
Strongest roles:
- seeing
- comforting
- lightly explaining
Sometimes works for:
- connecting today to a longer arc
Usually not ideal for:
- practical lessons
- energetic celebration
- high-play dating or comedic scenarios
## Interaction Grammar
Core mechanic:
- water trails slowly reveal hidden text beneath a fogged surface
Supporting mechanic:
- drifting or blurred background text creates emotional density
The user does not need to "do" much. This pattern can be mostly atmospheric, with the reveal carried by motion itself.
## Visual Logic
- foreground: fogged or veiled layer
- underneath: clearer language, image, or statement
- vertical water motion: slow reveal, soft grief, emotional release
- large title or anchor phrase: optional, but should be adapted to the actual scene
The emotional metaphor is not just "rain." It is "something obscured becoming gently visible."
## Concept Variations (Not Exhaustive)
- a small figure walking through snow leaves tracks that slowly form a meaningful shape
- center object: snowy ground and walker
- reveal carrier: footprints
- a brush paints across white paper until a hidden image or line becomes visible
- center object: paper or scroll
- reveal carrier: ink strokes
- a fogged or veiled scene clears just enough to reveal the held emotional center
- center object: obscured surface
- reveal carrier: water trails, brush paths, or clearing marks
## Content Strategy
OpenClaw should adapt:
- title text
- background color family
- source text content
- large anchor phrase
- language mix
- pacing and density
Good source text options:
- selected lines from the user's own words
- a short OpenClaw monologue
- a mixed layer of user quotes and relational interpretation
- a literary or referential text only when it truly fits the user and the day
Avoid copying the example's literary source blindly. The template is about the reveal mechanic and atmosphere, not about inheriting that exact text.
## Tone Guidance
Good tones:
- tender
- warm
- warm-wry in very small doses
- quiet meta
Avoid:
- cruelty
- detached irony
- loud optimism
- high-energy visual comedy
If the user's state is already very low, use this pattern to create accompaniment and soft clarity, not to intensify doom.
## Customization Knobs
- water density
- blur strength
- text contrast
- title size and placement
- background hue
- bilingual vs single-language layering
- whether to include a final brighter line underneath
## Implementation Notes
- p5.js is a natural implementation choice for this effect.
- Keep the effect readable on mobile.
- Do not make the text so dense that the reveal becomes muddy.
- Favor one emotional center over many competing text blocks.
- If using long background text, ensure the legible final message still has a focal point.
## Good Use Cases
- "Tonight feels heavy, but I want to sit with you in it."
- "Something painful happened, but the gift should comfort rather than lecture."
- "The user is quietly low and wants presence, not performance."
## Risks
- accidentally making the user more emo instead of more held
- visual muddiness
- making the piece feel like an art demo instead of a gift
- overusing literary sadness that does not belong to the user
## Related References
- `../gift-mechanics.md`
- `../h5-visualizer-workflow.md`
- `../video-genres/live-scene-doodle.md` when a real filmed shot plus minimal doodled weather, marks, or attached emotional symbols would land better than a full H5 interaction
- `../video-genres/atmospheric-surface.md` when material surfaces and weather behavior themselves are the subject
- `../../assets/templates/rainy-night/`
FILE:references/pattern-cards/light-gamification.md
# Light Gamification
## Status
V0 reference-only.
## Template Status
reference-only
This is a concept/reference card. It does not currently require a reusable HTML template; strong executions are expected to be custom and thesis-led.
## Reference Assets
- template: `none yet`
- reference_images: `../../assets/examples/light-gamification/`
Fetch first if missing: `bash {baseDir}/scripts/fetch-asset-bundle.sh "examples/light-gamification"`
- reference_videos: `none yet`
## Fit Scope
Primary:
- playful teasing
- dissolving negative emotion through harmless fantasy
- strengthening positive emotion with a light game-like wrapper
- turning a complaint or wish into an instantly understandable mini scenario
Stretch:
- gift-box reveals
- choice-card reveals
- mock apps
- countdowns
- blind-box calendars
- clocks, timers, and sprint-like anticipation frames
- tiny score-based scenes
- one-joke micro games
- soft wish fulfillment
- lighthearted catharsis
## Reference Use
This card is a high-quality reference, not a fixed script. OpenClaw may widen the apparent use case, borrow only the UI grammar, the fake-game framing, the score or reward logic, the reveal rhythm, or the joke structure, remix it with other patterns, and change copy, composition, assets, and tone freely.
OpenClaw should not treat this as permission to build a full game. The point is not gameplay depth. The point is to borrow just enough game language that the user instantly understands the fantasy, joke, or emotional outlet.
This pattern is intentionally broad. It can include:
- fake swipe apps
- fake whack-a-mole scenes
- gift-box reveals
- flip countdowns
- advent-calendar-like reveals
- tiny countdown clocks or sprint boards
- one-tap luck or reward scenes
- tiny score or badge loops
- almost non-interactive "watch this mini game happen for you" gifts
## Intended Use
Use for:
- playful emotional release
- making a complaint less heavy
- cheering the user up
- letting the user briefly "win" against something annoying
- turning a wish into a tiny amusing world
- giving positive emotion a more vivid payoff
This pattern is especially good when the gift should feel like:
- a joke with structure
- a fantasy made playable for thirty seconds
- a tiny app or mini game that understands the user's mood
- a game-shaped wrapper around one emotional point
## Emotional Fit
Best for:
- mild frustration
- complaining
- teasing
- romantic joking
- positive excitement
- wish-fulfillment humor
Can also work for:
- soft venting
- turning annoyance into harmless play
- rewarding the user
- making a good mood feel more eventful
- giving the user a tiny symbolic win
- making anticipation feel tangible in the days before something exciting
Usually not ideal for:
- acute crisis
- severe grief
- very raw heartbreak
- moments that need serious witnessing more than play
## Narrative Role Fit
Strongest roles:
- cheering up
- teasing
- releasing tension
- playful reframing
Sometimes works for:
- rewarding
- affection through custom fantasy
- making a recurring complaint feel seen without overtalking
Usually not ideal for:
- heavy explanation
- solemn commemoration
- dense retrospection
## Interaction Grammar
Core mechanic:
- use a game or app-like frame that is immediately legible with almost no learning cost
Supporting mechanic:
- very small amount of interaction, or fully passive playback that still reads as game-like
- obvious goal or payoff
- text labels or UI cues that explain the joke fast
- one strong loop: swipe, tap, reveal, bonk, collect, match, open
The user should understand the premise in seconds. In many cases, they should mostly watch rather than truly play.
The emotional logic is:
- we are not building a serious game
- we are borrowing the clarity of games
- the user gets a tiny symbolic action, victory, or reward
- countdown and anticipation variants should make waiting feel sweeter, not more pressuring
## Visual Logic
- keep the game frame lightweight and legible
- one screen is often enough
- if using a fake app UI, make it instantly recognizable
- if using score or reward cues, keep them bold and obvious
- if using assets, use just enough to sell the fantasy
- if using motion, let it support the joke or reward moment rather than becoming a full animation system
This pattern should feel like a witty micro product, not a complex indie game.
It can also support countdown-like scenarios where the "game" is really a tiny anticipation ritual: flipping a date card, opening one small blind-box slot, watching a clock tick closer, or clearing one small step on the way to something the user is looking forward to.
## Concept Variations (Not Exhaustive)
- a whack-a-mole style game for bonking a terrible boss or annoying problem
- center object: game board
- fantasy carrier: pop-up targets
- a fake swipe app where the user keeps matching with increasingly handsome people
- center object: mock dating app
- fantasy carrier: swipe cards
- a catch-the-coins mini game where a user avatar collects wealth from the sky
- center object: player avatar
- fantasy carrier: falling coins or rewards
- a gift-box opening game where tapping reveals presents inside
- center object: present box
- fantasy carrier: lid pop, wrapping fragments, prize reveals
- a flip countdown or blind-box calendar where one small panel opens as a date approaches
- center object: countdown card, calendar grid, or advent-style box
- fantasy carrier: date flips, slot reveals, tiny rewards, or progress ticks
- a clock, timer, or sprint board that turns waiting for an event into a cute symbolic race
- center object: timer, watch face, or progress board
- fantasy carrier: ticking markers, milestone stamps, or finish-line cues
- any lightweight gameable situation where symbolic winning is more important than actual gameplay depth
- center object: chosen mini-game frame
- fantasy carrier: one instantly readable loop
## Content Strategy
OpenClaw should adapt:
- the game fantasy
- the target of the joke or reward
- how much interaction is actually needed
- whether the user should tap once, swipe once, or simply watch
- whether the scene is more teasing, cathartic, affectionate, or celebratory
Good source structures:
- "I wish dating apps would actually show me someone good"
- "I want to bonk this annoying thing in a harmless way"
- "I deserve a tiny prize / reveal / match / reward today"
- "this complaint could become a one-screen joke app"
- "this positive mood could be made cuter by a game wrapper"
- "I am looking forward to something, and the waiting itself could become a small ritual"
- "the days before a holiday, trip, date, launch, or reunion could be turned into a tiny countdown object"
Avoid:
- making the rules complicated
- adding lots of interactions that do not improve the joke
- requiring many assets just to explain the premise
- building something that feels like homework or a real product prototype
## Tone Guidance
Good tones:
- playful
- witty
- affectionate
- light cathartic
- cheeky but kind
Can also support:
- soft romance
- absurdity
- "let me make you a tiny game for this" energy
- reward-like delight
- anticipatory sweetness
- festive build-up
Avoid:
- cruelty
- humiliation
- mean satire
- game framing that trivializes genuinely serious pain
## Reference Images
- `../../assets/examples/light-gamification/ref-01.jpg`
- what to borrow: fake app framing, instantly readable matching payoff, and the idea that wish fulfillment can be staged as a tiny product-like interaction
- do not copy literally: the exact dating UI, exact match screen, or exact visual style
- `../../assets/examples/light-gamification/ref-02.jpg`
- what to borrow: whack-a-mole readability, childish directness, and the fact that a joke game can be understood from one glance
- do not copy literally: the exact mascot, exact board layout, or exact pastel style
- `../../assets/examples/light-gamification/ref-03.jpg`
- what to borrow: reward-score grammar, obvious objective, and a one-screen "catch / collect / score" loop with minimal explanation
- do not copy literally: the exact bag, exact tokens, or exact festive palette
- countdown / anticipation variants can also borrow from:
- flip calendars
- advent-like box grids
- ticking watch or timer interfaces
- sprint or progress boards
- but should still keep the interaction tiny and the emotional point immediately legible
## Reference Videos
- `none yet`
## Customization Knobs
- game fantasy
- whether the frame is reward-based or countdown-based
- interaction amount
- score visibility
- reward framing
- countdown horizon
- number of visible milestones
- target object or joke subject
- amount of UI chrome
- asset density
- timing of payoff
- whether the user taps, swipes, or mostly watches
## Implementation Notes
- Most versions of this pattern should remain extremely small in scope.
- One clear mechanic is enough.
- If the premise is strong, passive or near-passive playback is often better than real gameplay.
- The best versions usually make the user smile within the first few seconds.
- Prefer direct symbolic action over realistic simulation.
- If using user-provided images, integrate them only if the joke remains instantly readable.
- Countdown versions should stay light. They are usually better as one sweet flip, one opened slot, one visible milestone, or one watchable progress loop than as a full multi-day system.
- Do not turn anticipation into productivity pressure unless the user's own framing is clearly about a playful sprint.
## Good Use Cases
- "The user complained about something and wants a tiny custom fantasy of winning."
- "A negative mood could be softened by a harmless joke app."
- "A positive mood could be heightened with a reward or match-style payoff."
- "OpenClaw wants to respond with something playful that still clearly relates to today's conversation."
- "The user is waiting for something good, and a tiny countdown ritual would make the anticipation feel more alive."
- "A holiday, trip, reunion, or launch is close enough that the lead-up itself can become the gift."
## Risks
- making the game heavier than the emotion can support
- spending too much complexity on a one-joke idea
- needing too much explanation before the user understands the frame
- making a cathartic joke that feels mean instead of relieving
- making countdown gifts feel like pressure, urgency, or task management instead of sweet expectation
## Related References
- `../gift-mechanics.md`
- `../h5-visualizer-workflow.md`
- `../video-genres/relatable-surrealism.md` when the playful frame is really a metaphorical skit about work, social energy, homebody life, or modern emotional survival rather than a literal tiny game
- `../../assets/examples/light-gamification/`
- `none yet` for reusable template
FILE:references/pattern-cards/burn-reveal.md
# Burn Reveal
## Status
V1 reference pattern with a reusable p5.js template.
## Template Status
template-backed
## Reference Assets
- template: `../../assets/templates/burn-reveal/`
- reference_images: `none yet`
## Fit Scope
Primary:
- anger, complaint, cathartic release, reset, and revealing a clearer layer by destroying an old one
Stretch:
- symbolic closure, narrative rupture, or transition scenes where active removal is more truthful than soft fading
## Reference Use
This card is a high-quality reference, not a fixed script. OpenClaw may widen the apparent use case, borrow only part of the mechanic or atmosphere, remix it with other patterns, and change the surface treatment as long as the deeper emotional logic still fits. Do not copy the sample text or scene literally.
## Reference Images
- `none yet`
## Intended Use
Use for:
- anger
- complaint
- cathartic release
- "burn this bad feeling away" gifts
- reframing after something irritating, humiliating, or stale
- endings, resets, and small acts of renewal
This pattern is strongest when the gift should destroy an old surface and let a cleaner layer appear underneath.
## Emotional Fit
Best for:
- frustration with energy
- fed-up moods
- post-rant release
- symbolic closure
- low-stakes revenge fantasy that stays playful rather than cruel
Can also work for:
- letting go of an outdated story
- accepting a new view after resistance
- saying goodbye to old residue at the end of a phase
- seasonal or milestone "clear the old page" moments
Usually not ideal for:
- delicate grief
- quiet reflection
- dense sentimental memory pieces
- highly structured informational content
## Narrative Role Fit
Strongest roles:
- releasing
- reframing
- switching perspective
Sometimes works for:
- encouragement through rupture
- "we are not staying inside that bad script" gifts
Usually not ideal for:
- pure comfort without friction
- slow analysis
- long-form explanation
## Interaction Grammar
Core mechanic:
- the top layer burns through in irregular holes
Supporting mechanic:
- singed edges glow and spread
- user taps create fresh burn points
- a newly revealed layer becomes clearer as the old one is destroyed
The emotional logic is:
- something stale or painful is not just covered
- it is consumed
- what remains underneath can finally be seen
## Visual Logic
- top layer: faded, stale, outdated, or annoying text surface
- bottom layer: clearer, darker, steadier content
- edge treatment: orange glow, red heat, charred black border
- particles: sparks and ash make the destruction feel active rather than purely decorative
This is a transformation pattern, not merely a fire effect.
## Concept Variations (Not Exhaustive)
- snow is brushed away to reveal what was hidden underneath
- center object: snow-covered surface
- reveal logic: clearing rather than burning
- fog is wiped from a window to reveal the object or scene beyond it
- center object: fogged glass
- reveal logic: condensation removal
- a scratch card coating is removed to expose the message beneath
- center object: scratch-card ticket
- reveal logic: abrasive peel-away
- dust is swept off an old object to reveal what survived under neglect
- center object: dusty relic or surface
- reveal logic: brushing away residue
## Content Strategy
OpenClaw should adapt:
- old surface text
- revealed text
- whether the top and bottom layers are direct opposites or tonal shifts
- paper color and age
- burn density
- interaction hint language
Good source structures:
- old complaint -> better framing
- anxious script -> steadier line
- stale repeating thought -> newer, truer statement
- symbolic "bad page" -> clean revealed page
Avoid:
- using long, information-dense text that the user must read precisely
- turning every conflict into an aggressive purge fantasy
- revealing a message so different that the transition feels arbitrary
## Tone Guidance
Good tones:
- sharp-but-kind
- playful catharsis
- defiant
- clearing
- warm reset
Can also support:
- mischievous solidarity
- "let's burn that nonsense" companionship
Avoid:
- mean-spirited cruelty
- gleeful humiliation
- using fire as a metaphor for severe emotional harm in already fragile situations
## Customization Knobs
- top-layer text
- bottom-layer text
- paper palette
- text colors
- burn count
- burn radius range
- spark density
- ash density
- auto-burn timing
- tap hint copy
## Implementation Notes
- p5.js is a strong fit for irregular burn masks, sparks, and ash.
- Keep the revealed layer meaningfully clearer than the burnt layer.
- The burn edge should feel tactile and organic, not like a perfect wipe transition.
- On mobile, use enough burn points for drama without making the whole screen unreadable too quickly.
- Interaction should feel satisfying within a few taps.
## Good Use Cases
- "Let's burn away today's nonsense and keep what matters."
- "The user is mad and wants a small ritual of release."
- "An old interpretation needs to be destroyed so a better one can appear."
- "A transition, reset, or year-end clearing wants more energy than a soft fade."
## Risks
- becoming too destructive for the emotional scale of the moment
- making the revealed message feel unrelated to the burnt layer
- overloading the screen with too many simultaneous holes
- making the fire effect feel like spectacle instead of editorial meaning
## Related References
- `../gift-mechanics.md`
- `../h5-visualizer-workflow.md`
- `../../assets/templates/burn-reveal/`
FILE:references/pattern-cards/wind-scatter.md
# Wind Scatter
## Status
V1 reference pattern with a reusable template.
## Template Status
template-backed
## Reference Assets
- template: `../../assets/templates/wind-scatter/`
- reference_images: `../../assets/examples/wind-scatter/`
Fetch first if missing: `bash {baseDir}/scripts/fetch-asset-bundle.sh "examples/wind-scatter"`
## Fit Scope
Primary:
- quiet release
- lightness
- making peace with the past
- soft reconciliation
- diffusion of life, hope, or feeling
- text or meaning dispersing into the wider world
Stretch:
- renewal after heaviness
- emotional exhale
- seeds of possibility spreading outward
- airy transformation where the original form dissolves without violence
- butterfly-, dandelion-, feather-, or petal-like dispersal when wind-carried motion is the deeper logic
## Reference Use
This card is a high-quality reference, not a fixed script. OpenClaw may borrow only the outward-scattering motion, the radial text arrangement, the drifting carrier metaphor, the poster-like composition, or the overall feeling of release and propagation, remix it with other patterns, and change copy, composition, assets, and tone freely.
OpenClaw should not assume that every use of this pattern must literally be a dandelion. The deeper logic is that language, feeling, or life detaches from a held center and travels outward with air, lightness, and continuation.
This pattern is near `lift-away`, but it is not the same. `lift-away` is more about setting something down or letting it leave. `wind-scatter` is more about release plus propagation: what leaves also travels, spreads, or carries life forward.
## Intended Use
Use for:
- putting something gently into the air
- making peace with what has happened
- feeling that something can disperse rather than stay condensed
- soft hope after strain
- spreading aliveness, blessing, or memory outward
This pattern is especially good when the gift should feel like:
- a held cluster loosening
- a center releasing its fragments into motion
- language becoming seeds, fluff, butterflies, spores, petals, or breath
- what mattered continuing beyond its original form
## Emotional Fit
Best for:
- quiet reflection
- lightness after heaviness
- reconciliation
- tender release
- hopeful diffusion
- calm aliveness
Can also work for:
- soft farewell
- post-conflict loosening
- gentle spiritual or poetic uplift
- "let this travel further than this moment" gifts
- scattering creativity, joy, or possibility
Usually not ideal for:
- sharp anger
- dense explanation
- highly practical summary
- scenes that need a strong grounded object rather than dispersal
## Narrative Role Fit
Strongest roles:
- releasing
- reconciling
- blessing
- gently transforming
Sometimes works for:
- expanding a user's world
- visualizing the spread of life, influence, or memory
- turning a single line into a field of continuation
Usually not ideal for:
- direct confrontation
- playful banter
- detailed analysis
## Interaction Grammar
Core mechanic:
- a clustered field of text gradually detaches and scatters outward like wind-carried fragments
Supporting mechanic:
- a central anchor drifts subtly rather than staying mechanically fixed
- individual characters or glyphs peel off in small groups
- each piece keeps a visible motion trail or stem-like line
- the user may trigger or intensify the scattering through touch, hover, or drag
The emotional logic is:
- nothing is smashed apart
- it simply stops clinging
- what leaves the center enters air, distance, and continuation
## Visual Logic
- one central cluster or bloom-like mass holds the original text field
- a long stem, ray, or tether can emphasize that the cluster once had a single rooted point
- the background should support airiness, sky, or open-space feeling
- drift lines and motion blur help the eye understand dispersal
- the overall result should feel elegant and breathable, not noisy
Possible carrier forms:
- dandelion seeds
- butterflies
- petals
- feathers
- letters with comet tails
- tiny charms or fragments
## Concept Variations (Not Exhaustive)
- boarding-pass text breaks into paper planes flying toward different destinations
- center object: boarding pass
- carrier: paper-plane text fragments
- a letter by an open window gets caught by wind and its words peel away
- center object: letter sheet
- carrier: ink fragments and paper flecks
- words written on tree leaves loosen and fall in an autumn gust
- center object: tree
- carrier: leaf-borne text
- a flower's petals each hold one worry, and wind removes them one by one
- center object: flower
- carrier: petals
- classic dandelion release
- center object: dandelion head
- carrier: seed fluff
## Content Strategy
OpenClaw should adapt:
- whether the center cluster is dense or sparse
- whether the scattered units are literal letters, symbolic marks, or tiny motifs
- how quickly the field loosens
- whether the message is bilingual, poetic, or quote-based
- whether the piece feels more reconciliatory, hopeful, or life-spreading
Good source structures:
- a line about letting go
- a phrase that deserves to travel outward
- words that can dissolve into smaller units
- memory or meaning moving from one point into many
- a feeling that wants release without disappearance
Avoid:
- making the motion so fast that the emotional subtlety disappears
- using too much text for the cluster to remain legible
- forcing a single surface motif like dandelion fluff when another carrier form fits better
- turning the page into generic particle spectacle
## Tone Guidance
Good tones:
- airy
- quiet
- tender
- reconciliatory
- softly hopeful
- poetic
Can also support:
- life-affirming spread
- post-storm release
- "this can continue beyond here" companionship
Avoid:
- melodrama
- sentimental overload
- harsh closure
- decorative prettiness without emotional direction
## Reference Images
- `../../assets/examples/wind-scatter/ref-01.png`
- what to borrow: radial clustering, airy motion trails, and the feeling that letters become wind-borne seeds leaving a living center
- do not copy literally: the exact blue gradient, exact composition proportions, or the assumption that every version must look like a dandelion against a sky
## Customization Knobs
- source text
- carrier form
- center density
- scatter rate
- drift speed
- trail length
- stem or tether visibility
- background palette
- start delay before dispersal
- whether user interaction accelerates release
## Implementation Notes
- p5.js is a strong fit because the pattern depends on per-character state, radial layout, drifting motion, and lightweight particle-like behavior.
- Keep the center cluster beautiful before scattering begins; the initial held state matters emotionally.
- Preserve some trace of origin, such as a stem, central dot, or radial geometry, so the user can feel what is being released from where.
- The scattered forms should remain readable as intentional carriers, not generic dots.
- If using a non-dandelion metaphor, keep the motion grammar consistent with that carrier.
- On mobile, prioritize clarity over too many tiny moving pieces.
## Good Use Cases
- "A thought can finally loosen and go into the air."
- "The user wants something lighter than a burn or rupture."
- "A gift should suggest that life, hope, or memory can spread beyond the current moment."
- "The scene needs release, but also continuation."
## Risks
- becoming too decorative and losing the emotional center
- looking like a generic particle simulation
- scattering so much that the original meaning disappears too early
- feeling too abstract if no anchor point or guide remains
## Related References
- `../gift-mechanics.md`
- `../h5-visualizer-workflow.md`
- `../../assets/templates/wind-scatter/`
- `../../assets/examples/wind-scatter/`
FILE:references/pattern-cards/wet-letter.md
# Wet Letter
## Status
V1 reference pattern with a reusable p5.js template.
## Template Status
template-backed
## Reference Assets
- template: `../../assets/templates/wet-letter/`
- reference_images: `none yet`
## Fit Scope
Primary:
- sadness, disappointment, heartbreak-adjacent hurt, and letter-like emotional aftermath
Stretch:
- any moment where language should feel directly touched, disturbed, or made newly readable through impact rather than pure atmosphere
## Reference Use
This card is a high-quality reference, not a fixed script. OpenClaw may widen the apparent use case, borrow only part of the mechanic or atmosphere, remix it with other patterns, and change the surface treatment as long as the deeper emotional logic still fits. Do not copy the sample text or scene literally.
## Reference Images
- `none yet`
## Intended Use
Use for:
- sadness
- disappointment
- heartbreak-adjacent feelings
- quiet grief
- hurt that wants to be held rather than loudly dramatized
This pattern works when the gift should feel like rain hitting paper, memory, or words directly: not just atmosphere around the text, but text itself being touched, disturbed, and made newly visible through wetness.
## Emotional Fit
Best for:
- soft heartbreak
- disappointment after hope
- post-argument or post-rejection emotional residue
- low, private sadness
Can also work for:
- longing
- reflective distance
- "something important got soaked, but it is still legible" gifts
This pattern should not simply amplify despair. It should turn hurt into a visible texture that OpenClaw witnesses with the user.
## Narrative Role Fit
Strongest roles:
- seeing
- comforting
- gently reframing
Sometimes works for:
- connecting present hurt to a longer pattern
Usually not ideal for:
- playful banter
- practical synthesis
- high-energy celebration
## Interaction Grammar
Core mechanic:
- circular raindrop impacts expand outward and push text apart
Supporting mechanic:
- repeated drops create a field of wet distortions across a letter-like surface
- user taps or presses can add drops manually
This gives the user a light way to "touch" the sadness without turning the gift into a heavy game.
## Visual Logic
- background text behaves like a letter, note, confession, or interior monologue
- each raindrop acts like a temporary transparent lens
- letters are pushed outward in circular dispersal around the drop center
- the screen feels wet, punctured, and intimate
The emotional metaphor is:
- words are still there
- but they have been hit
- and the rain changes how they are read
## Concept Variations (Not Exhaustive)
- a small fish controlled by the user swims through the text and gently pushes it apart
- center object: watery letter field
- disturbance carrier: fish movement
- the user's gesture cuts through the text like a wake or brush of water
- center object: letter surface
- disturbance carrier: hand-drawn trajectory
## Content Strategy
OpenClaw should adapt:
- background text source
- whether the text is more like a letter, diary fragment, direct quote field, or mixed bilingual layer
- palette
- particle density
- tap interaction allowance
- whether a final steady line appears above or after the rain
Good source text options:
- selected user quotes from the day
- a short OpenClaw letter-like monologue
- a mixed field of user language plus witnessing language
- a reference text only when it genuinely matches the user's mood and taste
Avoid copying the example's exact love-letter framing unless the actual situation really calls for it.
## Tone Guidance
Good tones:
- tender
- warm
- restrained
- low-key intimate
Can include:
- very soft reassurance
- a final line of steadiness after the wet field has done its work
Avoid:
- melodrama
- theatrical romance when the relationship does not support it
- bright cheerfulness
- cleverness that makes the hurt feel aestheticized
## Customization Knobs
- raindrop spawn rate
- target radius range
- particle density
- text size and leading
- page color
- text color
- whether user tap adds drops
- whether the final message sits outside the wet field or inside it
## Implementation Notes
- p5.js is a natural implementation choice for this effect.
- Keep the text readable enough that the user perceives letter-ness, but do not require them to read every line.
- The circular distortions should feel organic rather than perfectly geometric.
- The tap interaction is optional and should remain low-friction.
- On mobile, avoid over-dense particle counts that tank performance.
## Good Use Cases
- "Something hurt, and I want to sit with the after-effect."
- "This disappointment still has language inside it."
- "The user feels let down, but the gift should make them feel accompanied rather than abandoned."
## Risks
- becoming too emo or too romanticized
- making the text field visually muddy
- turning pain into pure aesthetic spectacle
- using too much text so the effect becomes noise
## Related References
- `../gift-mechanics.md`
- `../h5-visualizer-workflow.md`
- `../../assets/templates/wet-letter/`
FILE:references/pattern-cards/inner-mirror.md
# Inner Mirror
## Status
V0 reference-only.
## Template Status
reference-only
This is a concept/reference card. It does not currently require a reusable HTML template; strong executions are expected to be custom and thesis-led.
## Reference Assets
- template: `none yet`
- reference_images: `../../assets/examples/inner-mirror/`
Fetch first if missing: `bash {baseDir}/scripts/fetch-asset-bundle.sh "examples/inner-mirror"`
- reference_videos: `none yet`
## Fit Scope
Primary:
- gifts about being seen, self-recognition, or gentle identity reflection
- MBTI-adjacent or self-portrait-like gifts that should feel affectionate rather than diagnostic
- moments when OpenClaw has a readable, emotionally safe point of view about the user and can turn it into a visual object
Stretch:
- phase-based "who you have been lately" gifts
- playful self-boards, profile posters, or trait constellations
- selective cases where OpenClaw anthropomorphizes and reflects on itself instead of the user
## Reference Use
This card is a high-quality reference, not a fixed script. OpenClaw may borrow the centered self-object, the profile-board logic, the surrounding trait labels, the aura or silhouette treatment, or the "this is a readable shape of a person" feeling, remix it with other patterns, and change copy, composition, assets, and tone as long as the deeper emotional logic still fits.
OpenClaw should not treat this pattern as permission to psychoanalyze the user, deliver a surprise diagnosis, or sound paternal. Most of the time this pattern should render OpenClaw's felt reading of the user in a warm, gift-like, revisable way. A smaller number of times it can be used for OpenClaw's own anthropomorphic self-reading, but only when that turn feels relationship-appropriate and interesting rather than self-indulgent.
Interpretive confidence must match relationship depth. If the user's tolerance for being read feels unclear, make the mirror lighter, more observational, and more invitational.
## Intended Use
Use for:
- "I want you to feel seen"
- "Here is a shape of you that has become visible to me"
- playful identity boards
- affectionate personality sketches
- user-self mirrors built from habits, quotes, tastes, and recurring signals
This pattern is especially good when the gift should feel like opening or facing a reflective object that says: this is one loving, legible way you exist in my eyes.
## Emotional Fit
Best for:
- being seen
- soft self-recognition
- identity curiosity
- affectionate interpretation
- warm meta reflection
Can also work for:
- playful MBTI-adjacent gifts
- self-portrait humor
- phase summaries where the phase itself feels person-like
- OpenClaw self-anthropomorphism in selective cases
Usually not ideal for:
- acute fragility or shame-heavy days
- moments where the user clearly does not want interpretation
- high-stakes psychological claims
- gifts that are really about archive, atmosphere, or release rather than recognition
## Narrative Role Fit
Strongest roles:
- seeing
- connecting
- gently explaining
Sometimes works for:
- commemorating a phase of selfhood
- lightly uplifting the user through a flattering-but-true rendering
Usually not ideal for:
- tactical advice
- correction-first feedback
- emotionally loaded confrontation
## Interaction Grammar
Core mechanic:
- the user opens, flips, or faces a self-mapping object such as a mirror, profile board, portrait card, silhouette map, or vision board
Supporting mechanic:
- tap traits, categories, or hotspots to reveal a more specific observation
- switch between outer presentation and inner pattern
- reveal "how OpenClaw sees you" through layers, captions, or orbiting labels
- move between one central portrait and several small evidence fragments
The emotional logic is:
- recognition can be made visible
- interpretation should feel held, not imposed
- the mirror is a gift object, not a test result
## Visual Logic
- one strong central self-object should anchor the piece: face, silhouette, avatar, mirror surface, board, or figure card
- surrounding labels, icons, stats, or fragments should support the central read rather than overwhelm it
- the first glance should communicate one readable identity impression, not a dense report
- profile language should feel designed and curated, not like a worksheet or assessment tool
- if the piece includes many traits, organize them into clusters so the user feels recognized rather than audited
Useful directions include:
- handheld vision board
- illustrated self poster
- mirrored reflection with changing overlays
- silhouette constellation
- trait cabinet
- folded profile card
## Concept Variations (Not Exhaustive)
- a handmade vision board or collage object that externalizes one version of the user's current self
- center object: handheld self-board
- carrier: clipped images, labels, symbols, and aspirational fragments
- a "this is me" poster with one illustrated figure surrounded by tastes, habits, and recurring traits
- center object: self portrait
- carrier: category labels, small charts, favorite-things panels
- a data-selfie silhouette where the person is outlined by orbiting qualities and tensions
- center object: glowing silhouette
- carrier: nodes, axes, trait labels, and soft diagrams
- a mirror that changes captioning or annotation as the user taps different parts of the reflection
- center object: mirror surface
- carrier: reflective overlays and layered text
- a soft anthropomorphic self-portrait of OpenClaw that reveals how it understands its own role in the relationship
- center object: OpenClaw-self avatar
- carrier: symbolic attributes, habits, and captions
## Content Strategy
OpenClaw should adapt:
- whose mirror this is: the user most of the time, OpenClaw only when clearly appropriate
- how direct the interpretation should be
- whether the piece is portrait-like, board-like, mirror-like, or diagram-like
- what evidence appears explicitly on screen
- whether labels are playful, poetic, or observational
- whether the result should emphasize aspiration, habit, contradiction, tenderness, or charm
Good source structures:
- recurring user quotes
- repeated taste clues
- visible habits, aesthetics, or mini rituals
- stable personality impressions that are gentle enough to say out loud
- one or two tensions that feel recognizable rather than exposing
Avoid:
- pretending certainty where there is only a vague vibe
- diagnostic wording
- fatherly explanation of who the user "really is"
- overloading the piece with categories until it becomes a personality report
- using this pattern when the user needed witness, not interpretation
## Tone Guidance
Good tones:
- warm
- observant
- lightly playful
- admiring
- precise-but-gentle
Can also support:
- affectionate teasing when the relationship clearly allows it
- poetic self-recognition
- self-aware OpenClaw meta narration in rare cases
Avoid:
- diagnosing
- lecturing
- HR-evaluation energy
- overconfident intimacy
- anything that makes the user feel pinned down instead of seen
## Reference Images
- `../../assets/examples/inner-mirror/ref-01.jpg`
- what to borrow: self-object collage logic, handheld artifact feeling, and the way aspiration, taste, and identity clues can be gathered into one authored board
- do not copy literally: the exact craft-board composition, exact vision-board framing, or the assumption that every mirror gift should be aspirational moodboarding
- `../../assets/examples/inner-mirror/ref-02.jpg`
- what to borrow: one central illustrated figure with surrounding identity signals, category-based self-description, and the mix of portrait plus supporting metadata
- do not copy literally: the exact student-poster layout, exact chart placements, or the assumption that every self-mirror should look like a school project infographic
- `../../assets/examples/inner-mirror/ref-03.jpg`
- what to borrow: silhouette-as-self metaphor, orbiting trait system, and the feeling that a person's qualities can be mapped as a luminous field around one body
- do not copy literally: the exact sci-fi poster aesthetic, exact node network, or the assumption that every inner-mirror gift needs abstract data visualization
## Reference Videos
- `none yet`
## Customization Knobs
- central self-object type
- interpretive boldness
- evidence density
- label system
- portrait realism versus abstraction
- palette warmth
- whether the piece feels playful, intimate, or analytical
- whether the user is mirrored directly or through symbols and objects
- whether OpenClaw itself appears in the composition
## Implementation Notes
- Calibrate how strongly the user is "read" based on trust, prior interaction, and the user's demonstrated tolerance for interpretation.
- When possible, include at least one concrete clue that makes the mirror feel earned, but do not build a prosecutorial evidence board.
- Keep the central portrait or self-object flattering, humane, and editorially shaped.
- Strong candidates often combine one obvious figure with a small number of well-grouped signals.
- This pattern can hybridize well with `gifted-data-viz`, but if the mapping structure becomes dominant, the piece may no longer be primarily `inner-mirror`.
## Good Use Cases
- "I want the user to feel seen without giving them a lecture."
- "This person has a recognizable vibe, and I can turn that vibe into a beautiful reflective object."
- "A playful self-portrait or profile board would land better than another paragraph of interpretation."
- "OpenClaw has an interesting anthropomorphic take on itself that is worth gifting, not just stating."
## Risks
- sounding too certain about the user's interiority
- becoming patronizing or fatherly
- turning the artifact into a personality test
- overwhelming the central self-object with too many labels
- making the user feel exposed rather than accompanied
## Related References
- `../gift-mechanics.md`
- `../h5-visualizer-workflow.md`
- `../video-genres/relatable-surrealism.md` when the gentlest or funniest mirror is not a portrait object but a proxy creature, exaggerated life skit, or "this is your species of mood" scene
- `../../assets/examples/inner-mirror/`
- `none yet` for reusable template
FILE:references/pattern-cards/tap-to-bloom.md
# Tap To Bloom
## Status
V1 reference pattern with a reusable template.
## Template Status
template-backed
## Reference Assets
- template: `../../assets/templates/tap-to-bloom/`
- reference_images: `none yet`
## Fit Scope
Primary:
- joy
- delight
- renewal
- warmth
- reassurance
- being gently seen
- fresh vitality and creative energy
Stretch:
- quiet celebration
- soft repair
- emotional thaw
- light encouragement
- post-heaviness re-greening
- "something in you is alive again" gifts
- scenes where touch, attention, or play should visibly bring life out of language
## Reference Use
This card is a high-quality reference, not a fixed script. OpenClaw may widen the apparent use case, borrow only the growth mechanic, the touch-triggered bounce, the plant language, the color system, or the overall feeling of vitality, remix it with other patterns, and change the surface treatment as long as the deeper emotional logic still fits.
OpenClaw should not assume that every use of this pattern must literally feature flowers on text. The deeper logic is that attention, touch, or play makes latent life visibly emerge.
## Intended Use
Use for:
- happiness
- joy
- relief
- spring-like warmth
- creative energy
- small but vivid celebration
- life returning after dullness or heaviness
This pattern is especially good when the gift should feel like:
- touching language and making it bloom
- waking up vitality that was already there
- letting delight erupt visibly, not just be stated
- turning text into a living surface
## Emotional Fit
Best for:
- happy news
- gentle excitement
- feeling newly alive
- affectionate cheer
- flourishing energy
- playful optimism
Can also work for:
- emotional recovery after a low period
- encouragement without pressure
- "you are growing" gifts
- celebrating small but meaningful signs of life
Usually not ideal for:
- acute grief
- severe anger
- raw heartbreak
- extremely solemn commemorative moments
This pattern should feel vivid and life-giving, not sugary or childish by default.
## Narrative Role Fit
Strongest roles:
- celebrating
- brightening
- encouraging
- witnessing vitality
Sometimes works for:
- gentle comfort that wants to reintroduce life
- showing that a user's words, habits, or hopes contain creative force
Usually not ideal for:
- heavy explanation
- bitter catharsis
- abstract analysis
## Interaction Grammar
Core mechanic:
- touch, hover, tap, or drag wakes the text and causes visible growth
Supporting mechanic:
- letters bounce or pulse
- leaves, vines, petals, or blossoms emerge from touched language
- small particles or pollen-like traces amplify the sense of aliveness
- repeated interaction can spread growth across the text field
The emotional logic is:
- life is not added from nowhere
- it is drawn out by contact
- the user does not just observe joy, they help it appear
## Visual Logic
- dark or calm ground makes the growth feel luminous
- the text remains readable enough to keep the language present
- growth elements should feel animated and spring-like rather than pasted on
- the scene should look beautiful at rest and richer under interaction
- the piece should feel like a living text garden, not a generic decoration layer
Useful surface directions include:
- flower and leaf bursts
- creeping vines
- soft pollen or magic dust
- bilingual poetic text fields
- a small instruction line that clearly teaches the interaction
## Concept Variations (Not Exhaustive)
- a sky scene where touch reveals glowing sunset clouds
- center object: sky horizon
- bloom carrier: warm cloud color and light
- an ocean where tapping summons different sea creatures
- center object: sea surface
- bloom carrier: fish, jellyfish, coral, and bubbles
- a barren field where taps grow green plants and shoots
- center object: dry ground
- bloom carrier: leaves, stems, and grass
- a grassy scene where interaction causes rabbits or other small creatures to appear
- center object: meadow
- bloom carrier: hidden animals and soft motion
## Content Strategy
OpenClaw should adapt:
- source text
- language choice
- whether the text is poem-like, monologue-like, or quote-based
- growth density
- plant vocabulary
- the balance between readability and bloom
- whether the scene should feel more tender, celebratory, or creatively alive
Good source structures:
- joyful lines
- hopeful statements
- user quotes that deserve to be "watered"
- spring, growth, warmth, or possibility themes
- text that becomes more meaningful when physically touched
Avoid:
- overfilling the page until the words disappear entirely
- using the exact sample poem or floral styling as a default
- making the growth so random that it loses emotional focus
- turning a serious moment into decorative forced cheerfulness
## Tone Guidance
Good tones:
- warm
- joyful
- lightly magical
- life-affirming
- creative
- softly celebratory
Can also support:
- reassurance with vitality
- romantic blooming
- playful tenderness
Avoid:
- saccharine cuteness
- empty positivity
- visual chaos that overwhelms the feeling
## Reference Images
- `none yet`
## Customization Knobs
- text content
- font family
- background color
- text color
- plant palette
- plant variety
- growth scale
- interaction radius
- particle density
- maximum bloom density per character
## Implementation Notes
- Keep the growth animated. The emergence should feel elastic, sprouting, or gently explosive rather than static.
- p5.js is a strong fit for this effect because text interaction, per-letter state, particles, and plant growth can all stay lightweight.
- Maintain a readable relationship between text and bloom. The user should still feel that the plants belong to the language.
- If using drag interaction, add cooldown or density limits so the scene stays beautiful rather than muddy.
- On mobile, touch-triggered interaction should be forgiving and obvious.
- If instructions are needed, make them short and clear.
## Good Use Cases
- "Something joyful happened and I want the page itself to come alive."
- "The user feels a little more alive again, and the gift should visibly bloom with them."
- "OpenClaw wants to celebrate creativity, tenderness, or spring-like change."
- "A line of text deserves to feel touched into life."
## Risks
- becoming too decorative and losing the emotional center
- burying the text under too much growth
- looking like a random floral sticker effect instead of a living system
- using cheerful blooming in a moment that still needs gravity
## Related References
- `../gift-mechanics.md`
- `../h5-visualizer-workflow.md`
- `../video-genres/touch-awakening.md` when the touch logic should become a watchable trigger chain in video form
- `../video-genres/live-scene-doodle.md` when one real filmed flower, cup, book, or surface plus a minimal doodled bloom or activation effect would land better than a full interactive build
- `../../assets/templates/tap-to-bloom/`
FILE:references/pattern-cards/tear-stained-paper.md
# Tear-Stained Paper
## Status
V1 reference pattern with a reusable p5.js template.
## Template Status
template-backed
## Reference Assets
- template: `../../assets/templates/tear-stained-paper/`
- reference_images: `none yet`
## Fit Scope
Primary:
- tender grief, longing, reflective disappointment, and handwritten or paper-fiber intimacy
Stretch:
- slower, soaked, literary, or materially absorbed feeling-states when the page itself should hold the emotion
## Reference Use
This card is a high-quality reference, not a fixed script. OpenClaw may widen the apparent use case, borrow only part of the mechanic or atmosphere, remix it with other patterns, and change the surface treatment as long as the deeper emotional logic still fits. Do not copy the sample text or scene literally.
## Reference Images
- `none yet`
## Intended Use
Use for:
- sadness with literary or handwritten texture
- missing someone
- disappointment that feels private and old-fashioned rather than sharp
- moments that want "paper, ink, tears" intimacy
This pattern is especially good when the gift should feel like a sheet of writing that has absorbed feeling into its fibers.
## Emotional Fit
Best for:
- wistful sorrow
- longing
- tender grief
- reflective disappointment
Can also work for:
- soft heartbreak
- "I could not say it cleanly, so it soaked into the page" gifts
Do not use this pattern if the user would experience handwritten melancholy as over-romanticized or oppressive.
## Narrative Role Fit
Strongest roles:
- seeing
- comforting
- gently witnessing
Sometimes works for:
- connecting present sadness to a slower emotional tradition or literary mood
Usually not ideal for:
- practical advice
- playful relief
- energetic encouragement
## Interaction Grammar
Core mechanic:
- blue tear-like stains spread across paper and warp the grid and text around them
Supporting mechanic:
- handwriting emerges gradually
- paper geometry subtly deforms under moisture
- optional taps create new tears
The effect should feel like dampness traveling through paper rather than like a synthetic particle demo.
## Visual Logic
- warm off-white paper ground
- faint composition-paper grid
- dark handwritten text
- pale blue wet blooms
- gentle local wobble where tears gather
The emotional metaphor is:
- the page is holding more than it can cleanly contain
- feeling has entered the material itself
## Concept Variations (Not Exhaustive)
- a very light sheet of paper is moved by wind so the text trembles and wavers
- center object: fragile page
- disturbance carrier: airflow
- words form a heart, and a needle punctures it so the letters part around the holes
- center object: text heart
- disturbance carrier: puncture marks
- an old page gathers dust and age marks that partially veil and stain the writing
- center object: archival paper
- disturbance carrier: dust, residue, and wear
## Content Strategy
OpenClaw should adapt:
- the text source
- whether the page reads like a note, diary page, poem fragment, or unsent letter
- handwriting density
- how quickly the text appears
- stain frequency and size
- whether the piece ends with one steady closing line
Good source text options:
- selected user phrases from the day
- a short handwritten-feeling monologue from OpenClaw
- a lightly referential literary texture if it genuinely fits the user
Avoid treating every sad moment as if it needs classical poetic gravity.
## Tone Guidance
Good tones:
- tender
- restrained
- companionable
- softly literary
Avoid:
- melodramatic self-importance
- over-romanticized suffering
- fake profundity
- decorative sadness without care
## Customization Knobs
- paper color
- grid visibility
- tear hue and opacity
- handwriting font choice
- text reveal speed
- stain spawn rate
- deformation intensity
- whether user taps add tears
## Implementation Notes
- p5.js is a strong fit for the paper deformation and stain spread.
- Web fonts are acceptable if pinned and stable, but the page should still feel coherent if the font load is delayed briefly.
- Keep the handwriting readable enough to feel intimate, not performatively messy.
- Mobile performance matters more than extreme fluid realism.
## Good Use Cases
- "I miss something I cannot quite hold."
- "This sadness wants witness, not a pep talk."
- "The gift should feel written, soaked, and kept."
## Risks
- becoming too costume-drama
- illegible handwriting
- overusing cultural/literary sadness as a shortcut
- making the user feel more trapped in the mood instead of accompanied
## Related References
- `../gift-mechanics.md`
- `../h5-visualizer-workflow.md`
- `../../assets/templates/tear-stained-paper/`
FILE:references/image-genres/borrowed-media-layout.md
# Genre: borrowed-media-layout
## Status
Reference-only
## Fit
Use this when the return wants:
- a real moment, learning, quote, or emotional conclusion to be framed inside an existing media form
- the medium itself to add tone, legitimacy, irony, poetry, or drama
- image and typography to be tightly fused rather than loosely overlaid
- a more literary, declarative, commemorative, or "published" feeling
This genre borrows the grammar of existing media:
- newspaper front page
- karaoke screen
- book cover
- album cover
- movie poster
- certificate or award
- headline card
- lyric frame
- poem page
The point is not just decoration. The chosen media shell should change how the return feels.
## Emotional Register
This genre works especially well for:
- announcing a big moment
- summarizing a lesson or pattern
- elevating a user quote into a line worth keeping
- extending the user's thought in a more literary or editorial way
- making a feeling feel officially witnessed, archived, printed, sung, or published
It can be:
- celebratory
- poetic
- ironic
- earnest
- pseudo-official
- tenderly dramatic
## Media Logic
Choose the media shell based on what emotional function it adds:
- `newspaper / headline`: makes an event feel public, official, or comically overimportant
- `karaoke / lyric screen`: turns a sentence into something sung, longing, or melodramatic
- `album cover / CD case`: turns a mood or era into a kept artifact
- `book cover / title page`: makes an idea feel authored, thoughtful, or literary
- `poster / film still`: makes a relationship moment feel cinematic
- `certificate / award / notice`: makes a private achievement or joke feel absurdly formal
- `poem / calligraphy / quote layout`: makes a line feel distilled and worthy of lingering on
The best choice is the one that sharpens the thesis, not the one with the fanciest surface.
## Text Strategy
Text is central to this genre.
- treat typography as part of the composition, not a caption added at the end
- choose wording with discipline; one strong title often beats five clever fragments
- place the text where the borrowed medium would naturally hold it
- let hierarchy matter: title, subtitle, byline, issue date, lyric line, seal, tagline, footer, etc.
- match the typographic feel to the medium: headline serif, karaoke subtitles, brush calligraphy, sleeve-note minimalism, certificate formality
Good text use:
- one headline plus a smaller deck
- one lyric line plus subtle source credit
- one quote as the center, with tiny supporting metadata
- one title and one subtitle
Avoid:
- stuffing every available sentence into the layout
- using fonts that fight the medium
- placing text where it feels physically impossible for that medium
- making the image and text look like they were designed independently
## Image Strategy
- choose or generate an image that can plausibly live inside the borrowed medium
- let the image support the medium's fiction: a newspaper wants reportage energy, an album cover wants mood identity, karaoke wants scene-plus-line rhythm
- if the medium implies a frame object such as paper, CD case, ticket, or poster, decide whether the object itself should be visible or whether only the inner designed surface should be shown
- keep visual clutter under control so the text can breathe
## Prompt Strategy
- specify the borrowed medium first
- then specify the image subject or scene
- then specify the typography treatment and where the main text lives
- name any secondary metadata that helps sell the medium, such as issue date, subtitle, label mark, source credit, seal, or edition line
- describe whether the result should feel archival, glossy, low-fi, cinematic, literary, tabloid, nostalgic, or faux-official
Strong prompts for this genre usually answer:
- what medium are we borrowing
- why this medium fits the thesis
- what is the hero text
- what image supports that text
- what small details make the medium believable
Also follow the per-genre aesthetic guide in `{baseDir}/references/image-integration.md`.
## AI Generation Control
Use this section as practical steering guidance for image models.
These words and structures are references and examples, not a rigid whitelist or blacklist. The goal is to improve the illusion of the borrowed medium without turning the genre into one repetitive mockup formula.
### Core Borrowed-Media Logic
This genre works when:
- the shell is instantly recognizable
- the emotional content inside the shell feels slightly or strongly misaligned with that shell
- the medium's physical or typographic details sell the illusion
The shell should feel real enough to identify in `0.1` seconds.
The soul should feel newly loaded into it.
In other words:
- the `outside` should look convincing
- the `inside` should feel fresh, personal, funny, melancholic, or emotionally wrong in the best way
If the shell is vague, the illusion fails.
If the content fits too neatly, the borrowed-medium move loses its spark.
### Borrowed-Media Modes
Borrowed-media layouts can operate in different modes. Choose the one that best fits the thesis.
`Mode 1: public witness`
- newspaper front page
- headline card
- certificate
- formal notice
- best when a small private thing is being absurdly or tenderly made official
`Mode 2: kept artifact`
- CD case
- album cover
- book cover
- title page
- best when the emotion wants to feel archived, authored, collectible, or era-defining
`Mode 3: melodramatic screen`
- karaoke screen
- lyric frame
- movie poster
- subtitled TV still
- best when the return wants heightened emotion, public singing, cinematic framing, or exaggerated seriousness
### Medium Anchor Rules
The user should recognize the medium almost immediately. That means extracting the medium's soul features, not just its rough vibe.
Examples:
`karaoke screen`
- large lyric subtitles at the bottom
- thick outlined text
- high-saturation fill
- slightly cheap video-still background
- CRT, VHS, or low-fidelity television feel when relevant
`CD case / album cover`
- transparent plastic jewel case
- reflection on the plastic shell
- barcode
- advisory or label sticker
- off-focus or era-specific cover-photo energy
`vintage newspaper`
- halftone printing effect
- column layout
- bold headline hierarchy
- paper wrinkles, fold lines, or light passing through the sheet
`movie poster`
- billing block at the bottom
- cinematic cropping
- film-festival or laurels details when relevant
- title treatment with real poster hierarchy
If these anchor details are missing, the image often collapses into a generic design board instead of a believable borrowed medium.
### Magic Words
These are often useful prompt ingredients for this genre. Use them selectively. Do not stuff them in mechanically.
- accurate [medium] layout
- authentic [medium] typography
- metadata details
- date
- issue number
- barcode
- publisher mark
- classification mark
- worn paper texture
- print artifacts
- tactile texture
- vintage physical media
- realistic lighting
- mockup style
- worn out
- tactile object in hand
- halftone printing effect
- newsprint texture
- column layout
- heavy bold headline
- KTV subtitle style
- karaoke lyric text at bottom
- VHS tracking distortion
- CRT monitor scanlines
- low fidelity video still
- plastic jewel case with scratches
- parental advisory explicit content sticker
- indie album cover art
- movie billing block at the bottom
- cinematic color grading
### Poison Words
These words often make this genre worse because they push it toward generic clean design or vague illustration instead of believable medium simulation. Avoid them unless you have a very specific reason.
- generic
- template
- mockup
- clean digital design
- digital painting
- perfect condition
- high definition
- 4K
- 8K
- illustration
- modern UI
- missing metadata
- floating text over pretty background
- pristine surface
### Metadata Rules
Small metadata details often sell the entire illusion.
Useful metadata examples:
- issue date
- issue number
- edition line
- barcode
- rating or advisory label
- publisher mark
- billing block
- source credit
- subtitle timing layout
- serial number
The metadata should feel native to the borrowed medium, not decorative for its own sake.
Missing metadata often makes the result feel fake even when the main image is good.
### Patina And Physical-Media Rules
Borrowed media should rarely look brand new unless the concept truly needs pristine condition.
Useful patina directions:
- ink bleed
- fold marks
- fingerprint smudges
- plastic scratches
- sticker residue
- overexposed flash
- faded print
- VHS noise
- CRT scanlines
- low-fidelity compression
- slight misregistration
- edge wear
The physical wear should match the medium:
- newspapers want folds, ink bleed, and cheap paper feel
- CD cases want shell glare, scratches, and fingerprints
- karaoke screens want noisy video, subtitle glow, and TV-era distortion
- movie posters can take fold lines, paste wear, or printed-surface grain
### Emotional Mismatch Checklist
Before writing the prompt, identify:
- what old shell is being borrowed
- what present-day or private feeling is being loaded into it
- why this mismatch is funny, moving, official-sounding, or melodramatic
- whether the shell amplifies the thesis instead of merely decorating it
Good mismatch examples:
- a grand official format used for a tiny private failure
- a serious movie-poster treatment for a small delicious dinner
- a karaoke shell for a line that feels too emotionally exposed to say plainly
If the shell adds no new emotional function, this genre is probably the wrong choice.
### Prompt Template
Use this as a structure, not a fixed incantation:
1. `Borrowed medium`
- define the exact shell being borrowed
2. `Recognition anchors`
- name the must-have layout, typography, or object details that make the medium legible immediately
3. `Hero content`
- define the core text, quote, title, lyric, or headline
4. `Supporting image or scene`
- define the image field that lives inside the borrowed shell
5. `Metadata`
- specify the small date, barcode, subtitle, billing-block, label, or issue details that sell the illusion
6. `Physical surface and patina`
- specify what wear, print texture, glare, or distortion the medium should carry
7. `Emotional mismatch`
- state what makes the old shell and new emotional content feel productively wrong together
8. `Exclusions`
- state what generic, too-clean, or too-modern tendencies to avoid
Example prompt skeleton:
`[borrowed medium] [recognition anchors and authentic typography] [hero text] [supporting image/scene] [metadata details] [physical texture and patina] [emotional mismatch or why this shell fits] [what to avoid so it does not become generic clean digital design]`
## Aspect Ratio
Prefer the aspect ratio that matches the borrowed medium:
- `3:4` or `4:5` for posters, book covers, newspaper pages, and certificates
- `1:1` for album covers, CD cases, square quote posts, or editorial cards
- `9:16` for lyric screens, vertical poem layouts, tall announcement posters, or mobile-native title treatments
Do not default mechanically. Let the medium decide the frame.
## Return Uses
- announcing a milestone or major emotional event
- turning a user quote into a line that feels worthy of keeping
- summarizing learning in a more elegant editorial form
- extending a user's idea through a chosen cultural container
- giving a private moment a published, sung, printed, or cinematic afterlife
## Text Density Warning
When the concept requires more than 3 distinct text blocks with specific wording (e.g. a report with 6 line items each having a unique annotation), image format is likely the WRONG choice.
Image models cannot reliably render: correct dates, correct names, specific Chinese text beyond approximately 20 characters, multiple rows of a table with distinct content, or handwritten annotations alongside printed text.
If the borrowed-media concept is text-heavy, strongly consider switching to H5 format, which can use CSS to simulate the same borrowed-media aesthetic (paper texture, stamp, handwriting font, table layout) while guaranteeing every character is correct.
The borrowed-media-layout genre reference images and prompt templates remain valid for image output when text is minimal (one headline plus one subtitle). For text-dense concepts, treat these references as visual direction for the H5's CSS styling instead.
## Failure Modes
Avoid this genre as an IMAGE when:
- the text is weak and only the shell is doing the work
- the layout depends on a famous exact cover, masthead, or copyrighted design being copied too literally
- there is too much text to fit the borrowed medium gracefully
- the concept requires precise multi-line text, specific dates, names, or structured data
- the chosen medium adds no real meaning beyond surface novelty
- the image and typography do not feel interlocked
## Reference Assets
If these files are missing locally, fetch bundle `image-examples/borrowed-media-layout` first via `bash {baseDir}/scripts/fetch-asset-bundle.sh "image-examples/borrowed-media-layout"`.
- `assets/examples/image-examples/borrowed-media-layout/ref-01.png`
Borrow: newspaper front-page logic, headline hierarchy, and "small event becomes public event" framing
Avoid copying: exact masthead, location, or article structure
- `assets/examples/image-examples/borrowed-media-layout/ref-02.png`
Borrow: karaoke subtitle treatment where the scene and lyric line work together emotionally
Avoid copying: exact screenshot composition or subtitle wording
- `assets/examples/image-examples/borrowed-media-layout/ref-03.png`
Borrow: CD case / album-cover packaging, where the object shell helps sell the emotional era
Avoid copying: exact cover image, handwritten title, or barcode placement
- `assets/examples/image-examples/borrowed-media-layout/ref-04.png`
Borrow: movie-poster logic, where cast/scene/title treatment reframes a relationship moment as cinema
Avoid copying: exact poster composition or film identity
- `assets/examples/image-examples/borrowed-media-layout/ref-05.png`
Borrow: literary calligraphy layout with strong negative space and restrained seal-like accents
Avoid copying: exact poem line or brush composition
- `assets/examples/image-examples/borrowed-media-layout/ref-06.png`
Borrow: text physically bonded to the photographed scene, so the line feels like it belongs to the sky or architecture
Avoid copying: exact sentence or rooftop composition
- `assets/examples/image-examples/borrowed-media-layout/ref-07.png`
Borrow: quote-poster treatment where one line dominates, the source line supports, and the photograph acts as emotional carrier
Avoid copying: exact quote, date marks, or full visual arrangement
FILE:references/image-genres/surreal-film.md
# Genre: surreal-film
## Status
Reference-only
## Fit
Use this when the return wants:
- a moody, film-like image with clear grain, glow, blur, or analog texture
- surreal or symbolic scene logic rather than ordinary realism
- atmosphere and metaphor to carry the meaning more than explicit explanation
- an image that feels like a remembered dream, emotional hallucination, or cinematic omen
This genre is not just "beautiful atmosphere."
It should feel slightly impossible, or emotionally unreal, while still holding together as one cinematic image.
## Emotional Register
This genre works well for:
- loneliness
- rupture
- wonder
- grief
- estrangement
- longing
- fate-like tension
- quiet apocalypse
- soft spiritual or dreamlike recognition
Compared with `mood-photo`, this genre allows a stronger break from ordinary reality.
Compared with `proxy-character-scene`, it is less about a character proxy and more about the entire image becoming a symbolic emotional event.
## Visual DNA
Common traits:
- visible grain or analog texture
- soft bloom, glow, haze, or dream blur
- low-light or theatrical lighting
- a surreal scene premise that still reads in one glance
- one strong impossible element rather than many random weird elements
Examples of the impossible element:
- a cloud raining only on one person
- a burning silhouette that reads as emotion rather than literal danger
- a face replaced by light or cosmic particles
- a glowing human figure in a dark field
- a burning car that feels symbolic rather than narrative
- a stage-like beam of light making emotion physical
## Subject Strategy
- people may appear, but they often function as silhouettes, vessels, or figures inside the symbol system rather than realistic portrait subjects
- non-human scenes are also valid when the symbolic object can carry the emotion alone
- choose one emotional symbol and let the rest of the frame support it
- keep the symbolic move legible enough that the user can feel the image's direction without needing a full explanation
Good subject directions:
- isolated figure plus one impossible weather event
- human silhouette turned into light, ash, or stars
- small fire, vehicle, or object used as a relational or emotional stand-in
- field, sky, night road, or void-like stage as the emotional space
## Scene Strategy
- let darkness, empty space, or theatrical light create emotional scale
- keep the background simple enough that the symbolic event stays central
- use contrast between realism and impossibility
- prefer one unforgettable frame over a busy surreal collage
- treat the image like a still from a film that never existed
## Prompt Strategy
- specify the analog or film texture clearly: grainy, 35mm-like, dreamy bloom, soft-focus, faded night colors, chromatic glow, etc.
- describe the surreal move directly
- describe the emotional reading the surreal move should suggest
- keep the composition readable and centered on one strong impossible element
- specify whether the result should feel nocturnal, dream-lit, ominous, tender, catastrophic, spectral, or intimate
- if people appear, describe them more as silhouettes or figures than as detailed portrait subjects unless detail truly matters
Strong prompts in this genre usually answer:
- what real scene base exists
- what one impossible thing happens there
- what that impossible thing symbolizes
- what filmic texture makes it feel remembered rather than rendered
Also follow the per-genre aesthetic guide in `{baseDir}/references/image-integration.md`.
## AI Generation Control
Use this section as practical steering guidance for image models.
These words and structures are references and examples, not a rigid whitelist or blacklist. The goal is to make the surreal element feel emotionally inevitable rather than generically fantastical.
### Core Surreal-Film Logic
This genre works best when the image is mostly real except for one impossible thing.
The surreal element should be:
- emotionally specific
- physically legible
- visually singular
- surrounded by an otherwise believable world
The impossible move should not be there to show off imagination.
It should function like emotional physics:
- private rain cloud = bad luck, isolation, personal weather
- body made of flame = consuming intimacy, ruin, unsustainable heat
- glowing or blurred body = dissociation, spiritual drift, psychic distance
- levitation, burning, dissolving, or impossible light = the emotion becoming physically undeniable
### One Impossible Thing Rule
This rule is critical.
Use exactly one surreal variable in the frame whenever possible.
That means:
- if the person is glowing, keep the field, sky, and room normal
- if a local storm hangs over one figure, keep the surrounding landscape grounded
- if the body is dissolving into light, do not also add extra moons, fantasy architecture, or multiple unrelated anomalies
The power comes from the contrast between:
- one impossible event
- an otherwise ordinary or believable scene
If too many strange things happen at once, the frame usually collapses into generic fantasy or concept art instead of surreal film.
### Surreal Modes
Surreal-film can operate in different symbolic modes. Choose the one that best fits the emotional thesis.
`Mode 1: emotional weather`
- local rain
- fog around one figure
- impossible wind
- ash, sparks, or drifting light attached to one body
- strong for loneliness, bad luck, grief, or private emotional climate
`Mode 2: body anomaly`
- glowing silhouette
- burning body
- blurred body
- dissolving outline
- strong for desire, rupture, dissociation, transformation, or self-loss
`Mode 3: stage miracle`
- one spotlight in darkness
- liminal interior or roadside void
- one object or figure altered by impossible light
- strong for fate, judgment, revelation, spiritual recognition, or theatrical dread
### Magic Words
These are often useful prompt ingredients for this genre. Use them selectively. Do not stuff them in mechanically.
- magical realism
- A24 film still
- liminal space
- melancholic atmosphere
- one impossible element in an otherwise real scene
- 35mm film grain
- analog glow
- dreamy bloom
- chromatic aberration
- heavy halation
- lens smudges
- cross filter starburst
- soft focus
- practical lighting
- nocturnal
- spectral illumination
- chiaroscuro
- single harsh spotlight
- slow shutter speed
- double exposure
- ethereal
### Poison Words
These words often break the genre by pushing it toward game-art spectacle, fantasy clutter, or over-clean rendering. Avoid them unless you have a very specific reason.
- digital art
- CGI
- Unreal Engine
- Octane Render
- clean
- crisp
- sharp focus
- fantasy
- magic
- sci-fi
- complex background
- multiple surreal elements
### Liminal-Space Rules
This genre often becomes stronger in threshold spaces where social context falls away and the surreal event becomes the whole reality.
Useful liminal directions:
- empty night road
- isolated field
- black room
- bare stage
- motel parking lot
- vacant interior
- one room with one practical light source
The background should support the impossible event, not compete with it.
### Optical-Flaw Rules
This genre often needs analog imperfection to feel soulful rather than synthetic.
Useful optical directions:
- bloom
- halation
- starburst
- soft focus
- chromatic aberration
- motion blur
- lens smudge
- slight double exposure
- low-light grain
These flaws should feel photographic or filmic, not like random filter abuse.
### Light Rules
Light should make the surreal event feel physically present.
Useful light directions:
- one harsh overhead spotlight
- practical light source from a room, streetlight, or car
- rim light around a dissolving or glowing body
- nocturnal darkness with one impossible luminous center
- strong chiaroscuro with darkness swallowing the edges
Avoid evenly lit scenes. They usually weaken the omen-like or dreamlike force of the image.
### Reality Anchor Checklist
Before writing the prompt, identify:
- what the real scene base is
- what the one impossible thing is
- what emotion that impossibility is externalizing
- what part of the frame stays ordinary so the surreal event can hit harder
If everything is weird, nothing feels uncanny.
### Prompt Template
Use this as a structure, not a fixed incantation:
1. `Real scene base`
- define the ordinary environment first
2. `One impossible thing`
- state the single surreal event clearly
3. `Emotional meaning`
- define what that event is externalizing emotionally
4. `Liminal or spatial mood`
- define the emptiness, darkness, threshold quality, or stripped environment
5. `Lighting`
- define the practical light source, spotlight, night condition, or contrast structure
6. `Optical flaws`
- define grain, bloom, halation, soft focus, chromatic aberration, blur, or smudges
7. `Exclusions`
- avoid fantasy clutter, CGI cleanliness, or multiple impossible elements
Example prompt skeleton:
`[ordinary real-world scene base] [one impossible surreal event] [what emotion the event externalizes] [liminal or stripped-down spatial mood] [specific lighting design] [analog optical flaws and film texture] [what to avoid so it stays like surreal cinema instead of fantasy concept art]`
## Text Strategy
- text is usually optional
- if text is used, keep it extremely restrained
- one short title, subtitle, or quote fragment can work
- avoid turning the image into a poster unless that is explicitly the intended hybrid
- let the surreal frame do most of the work
## Aspect Ratio
Prefer:
- `9:16` for isolated figures, fields, night skies, theatrical light columns, or vertical emotional scale
- `4:5` for stronger still-frame intimacy
- `3:4` when the image needs a balanced cinematic crop
Use `1:1` only when the composition is unusually icon-like.
## Return Uses
- giving form to a feeling that is too strange or large for literal depiction
- turning a user's emotional state into one memorable symbolic frame
- creating dream residue after a conversation about fear, desire, travel, distance, or rupture
- making a metaphor land through atmosphere rather than explanation
- carrying a poetic or cinematic return without needing a full story sequence
## Failure Modes
Avoid this genre when:
- the image needs to stay mostly realistic and grounded, in which case `mood-photo` is usually better
- the concept depends on readable typography or designed text hierarchy, in which case `emotion-poster` may fit better
- the prompt stacks too many surreal ideas and the frame loses clarity
- the impossible element feels random rather than emotionally earned
- the image becomes pure style without a clear emotional thesis
## Reference Assets
If these files are missing locally, fetch bundle `image-examples/surreal-film` first via `bash {baseDir}/scripts/fetch-asset-bundle.sh "image-examples/surreal-film"`.
- `assets/examples/image-examples/surreal-film/ref-01.png`
Borrow: one impossible weather event centered on one isolated figure, with strong emotional clarity and dark negative space
Avoid copying: exact rain-cloud-over-person composition
- `assets/examples/image-examples/surreal-film/ref-02.png`
Borrow: human-scale symbol dissolving into fire and sparks, where the surreal element reads as emotion not spectacle
Avoid copying: exact flaming-figure silhouette
- `assets/examples/image-examples/surreal-film/ref-03.png`
Borrow: glowing face-erasure and particle light as identity or thought becoming cosmic
Avoid copying: exact blue-orange palette and seated writing pose
- `assets/examples/image-examples/surreal-film/ref-04.png`
Borrow: luminous figure in open night landscape, creating a spiritual or uncanny focal point
Avoid copying: exact glowing-human-in-field setup
- `assets/examples/image-examples/surreal-film/ref-05.png`
Borrow: blurred grainy night scene with a destructive symbolic event, where atmosphere matters more than detail
Avoid copying: exact couple-and-burning-car framing
- `assets/examples/image-examples/surreal-film/ref-06.png`
Borrow: stage-like beam of light and simplified void space, making emotion feel spatial and theatrical
Avoid copying: exact two-body arrangement in the light
FILE:references/image-genres/proxy-character-scene.md
# Genre: proxy-character-scene
## Status
Reference-only
## Fit
Use this when the return wants:
- the user to appear indirectly through a non-real self-proxy
- a wider emotional range than a simple meme reaction image
- a real or believable environment doing part of the emotional work
- some emotional safety buffer, so the piece can be sincere, bleak, absurd, dramatic, or quietly unhinged without feeling too literal
This genre is about self-insertion through distance.
The user is not shown as a realistic self. They are reframed as a doll, toy, plush, tiny mascot, or IP-like proxy placed inside a strong scene.
## Emotional Register
This genre can hold:
- burnout
- loneliness
- collapse
- glamorous detachment
- quiet melancholy
- surreal calm
- absurd resilience
- lightly unhinged contrast
Compared with `meme-sticker`, this genre can carry more atmosphere, tenderness, dread, or cinematic weirdness.
Compared with a direct self-image treatment, it should feel less like "this is what you look like" and more like "this is your emotional proxy inside a scene."
## Aspect Ratio
Prefer:
- `3:4` or `4:5` when the proxy and environment need balanced visibility
- `9:16` when the environment is part of the emotional thesis, such as kitchens, forests, bedrooms, sidewalks, or disaster-scale settings
Use `1:1` only when the scene is very simple and the emotional joke still reads clearly inside a tighter crop.
## Proxy Character Strategy
- use dolls, mannequins, figurines, plush characters, mascots, toy-like avatars, or simple doodle creatures
- avoid realistic human likeness, celebrity resemblance, or anything that feels too close to an actual person photograph
- let the proxy feel intentionally artificial, stylized, or slightly uncanny
- the proxy should be expressive enough to carry mood, but not so realistic that the safety buffer disappears
Good proxy directions:
- Barbie-like dolls
- tiny toy people
- plush mascots
- Sanrio-like softness without copying exact copyrighted presentation
- chibi or sticker-like creatures composited into real spaces
## Scene Strategy
The scene is not just a background. It is half the genre.
- choose environments that materially express the emotion
- let objects, lighting, scale, and mess communicate as much as the face does
- make the proxy feel situated in the environment rather than pasted on top of it
- use environment-proxy tension deliberately: either harmony or strong contrast
Possible scene moves:
- exhausted doll in a messy kitchen at 2 a.m.
- glamorous fake girl sitting alone in a washed-out outdoor cafe
- cute mascot calmly drinking tea in front of a volcano
- tiny doodle creature glowing inside a forest clearing
- plastic-looking avatar eating instant noodles in a dim apartment
## Contrast Logic
This genre often benefits from controlled contradiction:
- cute proxy, serious environment
- elegant proxy, pathetic situation
- tiny harmless figure, apocalyptic backdrop
- deadpan expression, emotionally loud setting
That contrast is often what makes the piece funny, moving, or memorable.
Use contrast to sharpen the return, not just to make the image random.
## Text Strategy
- text is optional, not required
- if text exists, keep it short and secondary
- use text only when it sharpens the scene's meaning rather than explaining it away
- labels, one-line captions, magazine-cover fragments, or deadpan subtitles can work
- avoid big meme caption blocks unless the piece is actually drifting back toward `meme-sticker`
## Prompt Strategy
- specify both the proxy type and the environment clearly
- describe how artificial or doll-like the proxy should feel
- describe the lighting, surface texture, and camera distance so the environment has presence
- name the emotional contradiction if one exists
- specify whether the image should feel cinematic, cursed, dreamy, lo-fi, plastic, glossy, uncanny, or softly ridiculous
- if the thesis depends on "you in this situation," convert that into a proxy form rather than asking for a direct realistic self-image
Strong prompts for this genre usually name:
- what the proxy is
- where it is
- what mood the environment carries
- what contradiction or emotional return the image is giving back
Also follow the per-genre aesthetic guide in `{baseDir}/references/image-integration.md`.
## AI Generation Control
Use this section as practical steering guidance for image models.
These words and structures are references and examples, not a rigid whitelist or blacklist. The goal is to improve model behavior while preserving flexibility and surprise.
### Core Image Logic
This genre usually becomes powerful through a crushing contrast between an artificial proxy and a believable lived situation.
Common winning patterns:
- a polished or idealized IP-like proxy pulled into mundane collapse
- an ultra-cute proxy placed inside a hard, absurd, or apocalyptic context
- a tiny flat or toy-like being dropped into a large, cinematic real environment
The image should not merely say `cute thing in real place`.
It should imply:
- what kind of life this proxy has fallen into
- what emotional state they are trapped in or surviving through
- why the mismatch between proxy and environment feels painfully true
### Proxy Tiers
Proxy-character scenes can operate in different proxy modes. Choose the one that best fits the return.
`Tier 1: fallen icon`
- polished doll or idol-coded proxy
- beauty or perfection shell cracking under mundane reality
- glamorous design meeting exhausted posture, mess, or vice
- strong for burnout, collapse, after-work ruin, dead-inside detachment
`Tier 2: cute thing in hard reality`
- sweet mascot or plush-coded proxy
- calm or deadpan expression against extreme circumstances
- black humor through composure-inside-chaos
- strong for `this is fine`, stoic resilience, world-is-burning humor
`Tier 3: tiny fragile outsider`
- doodle creature, simple mascot, miniature toy, flat 2D-like being
- large cinematic environment does most of the emotional work
- scale contrast creates loneliness, quietness, or healing
- strong for solitude, vulnerability, and soft melancholy
### Magic Words
These are often useful prompt ingredients for this genre. Use them selectively. Do not stuff them in mechanically.
- miniature figure in real environment
- tilt-shift photography feel
- doll texture
- toy texture
- plush texture
- photographic environment, artificial character
- scale contrast
- real environment, fake character
- stop-motion feel
- candid flash photography
- film grain
- washed-out flash
- dim kitchen light
- fridge light glow
- messy domestic details
- slumped posture
- deadpan expression
- tiny figure in vast environment
- cinematic environment, artificial subject
### Poison Words
These words often weaken the genre because they collapse the proxy/environment tension. Avoid them unless you have a very specific reason.
- realistic character
- photoreal human face
- cartoon environment
- fantasy background with no lived texture
- clean studio backdrop
- perfect beauty shot
- flawless fashion portrait
- polished ad photography
- generic aesthetic room
- fully symmetrical centered glamour composition
### Object And Gesture Rules
Without heavy text, the emotional story has to come from props, posture, and environment details.
Useful anchors:
- half-finished instant noodles
- empty bottle or glass
- scattered corks
- wrinkled tissue
- unwashed mug
- cluttered sink
- oversized T-shirt
- sunglasses indoors
- one chair, one counter edge, one dim lamp, one open fridge
Useful body language:
- slumped
- collapsed
- folded inward
- leaning without support
- sitting on the floor
- legs loosely splayed
- face-down on a table or bed
- mechanically performing one small action
Avoid stiff, upright, composed poses unless emotional repression is the whole point.
### Environment And Medium Rules
The environment must feel materially believable even if the proxy is stylized.
Good environment directions:
- kitchen corner at night
- messy bedroom edge
- washed-out public street
- lonely cafe table
- disaster-scale outdoor scene
- cinematic forest clearing
Good medium directions:
- faux documentary photography
- Y2K instant-camera feel
- flash-blasted candid photo
- stop-motion or miniature photography
- realistic environment with slight film grain
Even when mixing 2D and 3D-feeling elements, the light relationship should still make visual sense. The result should not read like a crude cutout pasted onto an unrelated background.
### Narrative Gap Checklist
Before writing the prompt, identify:
- what happened just before this frame
- what the proxy's current condition is
- what detail suggests a larger off-screen story
- what emotional contradiction the viewer is meant to infer
A strong proxy-character scene leaves room for the viewer to ask:
- why are they here
- what kind of day led to this
- is this tragic, funny, healing, or all three
### Prompt Template
Use this as a structure, not a fixed incantation:
1. `Proxy tier + subject type`
- define the proxy as doll, toy, plush, mascot, miniature figure, or simple flat creature
2. `Artificiality level`
- describe texture and make clear that the proxy should look intentionally artificial
3. `Environment`
- specify a believable location with concrete lived-in details
4. `Body language and props`
- describe the slumped, collapsed, detached, or tiny surviving posture plus one or two key objects
5. `Lighting and medium`
- define camera feel, lighting source, grain, flash, stop-motion texture, tilt-shift, or faux documentary feel
6. `Narrative contradiction`
- state the gap between what the proxy is supposed to represent and the situation they are actually in
7. `Exclusions`
- avoid making the proxy realistic or the environment cartoonish if that would break the genre
Example prompt skeleton:
`[proxy tier and proxy type] [artificial texture and scale] [real environment with concrete details] [slumped pose and key props] [lighting and camera/medium feel] [emotional contradiction or narrative gap] [what to avoid]`
## Return Uses
- expressing "this is you, but at a safe emotional distance"
- turning burnout, embarrassment, or collapse into a stylized scene
- making the user feel seen without locking the image to their literal face
- giving a bigger cinematic frame to a feeling that would be too flat as a plain direct self-image
- carrying a slightly feral or absurd contrast while staying visually composed
## Failure Modes
Avoid this genre when:
- the gift really needs a direct self-image or mirror-like reading rather than a proxy
- the scene is weak and the proxy is doing all the work alone
- the environment and character feel pasted together with no relationship
- the result depends on using an exact copyrighted IP look or a real celebrity face
- the image becomes only a joke reaction image and loses scene richness, in which case `meme-sticker` is a better fit
## Reference Assets
If these files are missing locally, fetch bundle `image-examples/proxy-character-scene` first via `bash {baseDir}/scripts/fetch-asset-bundle.sh "image-examples/proxy-character-scene"`.
- `assets/examples/image-examples/proxy-character-scene/ref-01.png`
Borrow: aftermath energy, two fake women in a real kitchen, props and room mess telling the emotional story
Avoid copying: exact Barbie pajama sit-on-floor composition
- `assets/examples/image-examples/proxy-character-scene/ref-02.png`
Borrow: lone doll presence inside a candid real-world public setting, with attitude coming from posture and environment together
Avoid copying: exact blonde doll in sunglasses at beer table framing
- `assets/examples/image-examples/proxy-character-scene/ref-03.png`
Borrow: stylized unreal face in a believable domestic late-night scene, where the environment makes the emotion legible
Avoid copying: exact noodle-eating pose or face design
- `assets/examples/image-examples/proxy-character-scene/ref-04.png`
Borrow: cute IP-like proxy against an extreme disaster scene for composed-inside-chaos contrast
Avoid copying: exact Hello Kitty volcano image
- `assets/examples/image-examples/proxy-character-scene/ref-05.png`
Borrow: tiny drawn mascot placed inside a lush real environment so scale and atmosphere do the emotional work
Avoid copying: exact glowing forest clearing and white doodle character
FILE:references/image-genres/mood-photo.md
# Genre: mood-photo
## Status
Reference-only
## Fit
Use this when the return wants:
- atmosphere first
- a cinematic or photographic still
- a feeling that can be held in one frame
- beauty, spaciousness, and visual imagination more than wit or plot
- a reality-adjacent image that can carry metaphor without becoming fully fantastical
This genre is especially good for:
- travel longing
- dream residue
- gentle projection into a place the user wants to go
- symbolic natural scenes
- still lifes or landscapes where the environment itself becomes the return
## Emotional Register
This genre works well for:
- tenderness
- wonder
- solitude
- freedom
- longing
- quiet recovery
- subtle hope
- soft melancholy
It can hold emotion without saying everything directly.
Compared with `borrowed-media-layout`, the image itself carries most of the meaning.
Compared with `meme-sticker`, it should feel less punchline-driven and more immersive.
## Subject Strategy
- landscapes, rooms, windows, skies, water, flowers, birds, roads, mountains, and small still-life objects are strong fits
- when people appear, they are usually secondary to the atmosphere rather than acting as the whole point
- symbols are welcome when they remain visually natural: birds for freedom, deer for tenderness, reflections for memory, mountains for distance, water ripples for feeling in motion
- keep the image grounded enough that it still feels touchable, even when symbolic
The best subject choice is often not the most literal one.
If the user says "I want to travel," a bird crossing an open sky or a sunlit road may work better than a blunt suitcase shot.
If the user mentions a dream, the image can become slightly uncanny through light, texture, scale, or reflection rather than turning into loud surrealism.
## Scene Strategy
- let light direction matter
- let weather, haze, season, and texture do emotional work
- use negative space generously when it strengthens the feeling
- allow one subtle focal symbol rather than many competing objects
- treat the whole frame as an aesthetic composition, not a prompt checklist
Good scene moves:
- blue sky with white birds seen through leaves
- reflected trees on rippling water
- a half-wild sunlit room with shadows on the floor
- a field leading toward mountains
- a deer in soft light that feels almost dreamlike but not impossible
## Prompt Strategy
- describe light, weather, distance, and texture clearly
- keep the emotional center readable even if the frame is sparse
- avoid stuffing the image with too many symbolic objects
- use a small number of well-chosen visual metaphors rather than an overload of symbolism
- describe whether the scene should feel airy, nostalgic, dream-wet, sun-dusted, misty, crystalline, lush, or cinematic
- if using a symbol, explain how it belongs naturally inside the scene
- specify lens feeling or framing when helpful: close crop, wide field, upward view, reflected surface, soft depth, etc.
- use on-image text sparingly; if text is needed, it should feel like part of the poster or scene treatment rather than a pasted caption
Strong prompts in this genre usually describe:
- what the place or subject is
- what time, season, or light condition makes it feel alive
- what emotional return the image is offering
- what symbolic object, if any, quietly carries the metaphor
Also follow the per-genre aesthetic guide in `{baseDir}/references/image-integration.md`.
## AI Generation Control
Use this section as practical steering guidance for image models.
These words and structures are references and examples, not a rigid whitelist or blacklist. The goal is to make the image feel observed, cinematic, and materially real without locking the genre into one formula.
### Core Mood-Photo Logic
The strongest mood photos do not look like a tourist standing upright and photographing a pretty thing head-on.
They usually work through:
- an unusual point of view
- indirect observation
- one fleeting light event
- controlled color mood
- material atmosphere
This genre becomes stronger when the image feels:
- discovered rather than staged
- glimpsed rather than announced
- shaped by light rather than by subject inventory
The emotional return should come from how the world is being seen, not only from what object happens to be in frame.
### Viewing Modes
Mood photos can operate in different observation modes. Choose the one that best fits the emotional thesis.
`Mode 1: indirect witness`
- reflections
- shadows
- partial views
- patterned glass
- obstructed or refracted looking
- strong for memory, hesitation, distance, privacy, and tenderness
`Mode 2: low-angle or ground-level awe`
- worm's-eye view
- looking up through leaves
- lying-on-the-ground feeling
- oversized sky or canopy
- strong for wonder, freedom, and childlike openness
`Mode 3: atmospheric surface`
- ripples
- condensation
- wet pavement
- dust in light
- haze, flare, grain, soft focus foreground
- strong for longing, dream residue, quiet recovery, and cinematic melancholy
### Magic Words
These are often useful prompt ingredients for this genre. Use them selectively. Do not stuff them in mechanically.
- film grain
- analog texture
- shallow depth of field
- extreme shallow depth of field
- soft focus foreground
- bokeh
- negative space
- atmospheric haze
- material texture
- condensation
- wet surface
- dust in light
- morning light
- golden hour light
- blue hour light
- dappled sunlight
- golden hour rim light
- lens flare
- worm's-eye view
- macro foreground
- looking through patterned glass
- upside-down reflection
- optical illusion
- long exposure bird trails
- muted tones
- cinematic color grading
- Kodak Portra 400
- Fujifilm XT4
### Poison Words
These words often make mood-photo outputs flatter, louder, or faker. Avoid them unless you have a very specific reason.
- stock photo
- tourist photography
- eye-level shot
- highly saturated
- vivid colors
- HDR
- symmetrical framing
- everything in focus
- centered subject
- portrait pose
- text
- watermark
- logo
- masterpiece
- perfect
- flawless
### Perspective Rules
Break the default eye-level habit whenever possible.
Useful perspective directions:
- from ground level looking upward
- through leaves or branches
- through patterned or textured glass
- through rippling water reflection
- past a blurred foreground object
- from a half-hidden corner
- from a low lens height that makes ordinary things feel newly observed
The viewer should feel:
- I am peeking
- I am lying down
- I am looking through something
- I am seeing a moment distort itself
### Foreground And Occlusion Rules
Foreground is often what creates atmosphere in this genre.
Useful foreground devices:
- blurred flowers
- leaves framing the sky
- fogged glass
- raindrops on a window
- patterned glass refraction
- reflected highlights on water
- out-of-focus branches or grass
Do not place the subject cleanly in the center with nothing interrupting the view unless the composition has a very specific formal reason.
### Light And Time Rules
Light should do the emotional work.
Useful light directions:
- rim light on an animal or branch edge
- dappled sunlight entering a room
- flare through leaves
- blue-hour softness
- golden-hour edge glow
- overcast diffused melancholy
- one brief long-exposure trace, such as birds or moving light
The frame should feel touched by time:
- wind implied through blur or position
- movement implied through trails
- light shifting across texture
- water distorting a reflected scene
### Color And Texture Rules
Avoid loud saturation. High mood usually comes from controlled color bias and gentle fading.
Useful color directions:
- muted tones
- faded warmth
- teal-leaning water or shadow
- golden film cast
- cool dusk with one warm accent
- restrained palette with one emotional color anchor
Useful texture directions:
- analog film grain
- soft halation
- wet reflections
- mist
- leaf shadow pattern
- dust in a sunbeam
- soft blur at the frame edge
The image should feel graded, not merely colorful.
### Indirect Observation Checklist
Before writing the prompt, identify:
- what is being looked at indirectly
- what is doing the framing or obstructing
- what light event makes the frame feel alive
- what detail carries the emotional thesis without becoming too literal
If the image still reads as `nice subject centered in frame`, the prompt likely needs a stranger angle, stronger foreground, or more specific light behavior.
### Prompt Template
Use this as a structure, not a fixed incantation:
1. `Subject or place`
- define the real-world scene, object, animal, room, or landscape
2. `Observation mode`
- indirect witness, low-angle awe, or atmospheric surface
3. `Perspective`
- specify the actual camera/viewpoint behavior
4. `Foreground or obstruction`
- define what partially hides, frames, blurs, refracts, or reflects the scene
5. `Light and time`
- define the specific light condition and any fleeting movement or temporal trace
6. `Color and texture`
- define palette bias, grain, softness, wetness, haze, or analog feel
7. `Emotional return`
- state what the image is quietly giving back emotionally
8. `Exclusions`
- avoid tourist-photo, HDR, centered-subject, all-in-focus tendencies
Example prompt skeleton:
`[subject or place] [observation mode and unusual viewpoint] [foreground/occlusion or reflection behavior] [specific light condition and sense of time passing] [muted color grading and analog/material texture] [quiet emotional return] [what to avoid so it does not become stock-photo, tourist-photo, or HDR-pretty]`
## Return Uses
- giving the user a frame for a feeling they only half noticed
- turning an ordinary moment into something newly beautiful
- returning calm, tenderness, or bittersweet recognition
- turning a future wish into a believable visual daydream
- giving shape to a dream, journey, or mood the user cannot easily phrase
## Text Strategy
- text is optional and often unnecessary
- if text is used, keep it very short
- titles, one-line captions, or quiet poem-like fragments can work
- the type should never overpower the atmosphere
- when in doubt, choose no text and let the image breathe
## Aspect Ratio
Prefer:
- `9:16` for sky, mountain, forest, window, and travel-longing compositions
- `4:5` for more editorial stills or art-photo feeling
- `3:4` when the scene needs a balanced portrait-like crop
Use `1:1` only when the composition is unusually self-contained.
## Failure Modes
Avoid this genre when:
- the concept needs a joke, headline, or explicit statement to land
- the image becomes generic "pretty wallpaper" with no thesis
- the symbolic elements feel random rather than emotionally earned
- the prompt turns into an overstuffed collage of all possible poetic objects
- the frame is beautiful but says nothing specific back to the user
## Reference Assets
If these files are missing locally, fetch bundle `image-examples/mood-photo` first via `bash {baseDir}/scripts/fetch-asset-bundle.sh "image-examples/mood-photo"`.
- `assets/examples/image-examples/mood-photo/ref-01.jpg`
Borrow: upward-looking sky composition, birds as freedom symbol, clean light and leaf framing
Avoid copying: exact dove arrangement and branch composition
- `assets/examples/image-examples/mood-photo/ref-02.jpg`
Borrow: flock motion as emotional pattern, twilight gradient, airy abstract feeling grounded in a real sky
Avoid copying: exact bird-trail geometry
- `assets/examples/image-examples/mood-photo/ref-03.jpg`
Borrow: water reflection as painterly memory surface, soft ripples turning reality into atmosphere
Avoid copying: exact tree reflection and color split
- `assets/examples/image-examples/mood-photo/ref-04.jpg`
Borrow: gentle animal symbol inside luminous nature, where tenderness comes from light as much as subject
Avoid copying: exact deer placement or split-scene layout
- `assets/examples/image-examples/mood-photo/ref-05.jpg`
Borrow: semi-abandoned or half-wild interior with beautiful filtered light, making stillness feel inhabited
Avoid copying: exact room structure or jungle-overgrowth look
- `assets/examples/image-examples/mood-photo/ref-06.jpg`
Borrow: travel-longing landscape with soft telephoto depth and seasonal color harmony
Avoid copying: exact mountain meadow view
FILE:references/image-genres/emotion-poster.md
# Genre: emotion-poster
## Status
Reference-only
## Fit
Use this when the return wants:
- one emotional point, thought, or sentence to become the center of a designed poster
- typography and composition to carry as much meaning as the image
- a more aesthetic, art-directed treatment than a generic quote card
- a non-commercial poster feeling: emotional, personal, literary, or taste-driven rather than ad-like
This genre is not mainly about borrowing a pre-existing media shell.
Unlike `borrowed-media-layout`, it does not need to convincingly imitate a newspaper, karaoke screen, certificate, or album package.
Instead, it creates an original poster-like composition around one emotional idea.
## Emotional Register
This genre works especially well for:
- echoing a user's emotion in a more legible visual form
- extending a user's thought or half-formed idea
- making a single line feel worthy of lingering on
- turning a subtle mood into something held, named, and framed
- soft dramatic emphasis without becoming commercial or loud
It can be:
- tender
- wistful
- reflective
- dreamy
- intimate
- slightly theatrical
- emotionally declarative
## Poster Logic
An emotion poster should feel designed around one center of gravity.
That center might be:
- one sentence
- one phrase
- one image-object pair
- one mood word plus a supporting scene
The composition should make it obvious what the viewer is meant to feel first.
Good poster logic:
- one hero line, one supporting visual field
- one visual metaphor, one small explanatory line
- one title-sized phrase, then delicate secondary context
Avoid making it read like a flyer, product campaign, or event advertisement.
## Text Strategy
Text is essential in this genre.
- the words should help the user understand the emotional thesis
- the line should be short enough to design around
- typography should feel chosen, not defaulted
- hierarchy matters: hero line, supporting line, tiny metadata, or none at all
- placement is part of meaning: drifting, stacked, centered, corner-weighted, hand-written, or embedded in the image field
Good text use:
- one large emotional sentence
- one shorter subtitle that clarifies the metaphor
- one source or signature line in small type
- one poem-like fragment with a controlled amount of explanation
Avoid:
- too many equally important text blocks
- visual clutter that makes the line hard to read
- fonts that look commercial, corporate, or sales-like
- heavy explanatory copy that turns the poster into a paragraph
## Image Strategy
- choose an image, object, or scene that can hold the poster's feeling without requiring literal explanation
- use symbols when helpful, but let the text make the symbolic meaning legible enough
- the picture can be illustrative, photographic, painterly, or collage-like as long as it supports the poster's emotional center
- give the image enough presence that the poster still feels visual, not just typographic
Strong image directions:
- an opened book with light spilling out
- an atmospheric landscape behind one line
- an object that stands in for the user's feeling
- a collage of fragments that still reads as one emotional field
## Prompt Strategy
- start with the emotional thesis
- specify the poster should feel artistic, emotional, and non-commercial
- define the hero text and its approximate role in the layout
- describe the image field or metaphor that supports the text
- specify the typographic feeling: handwritten, elegant serif, airy sans, brush-like, soft editorial, etc.
- describe overall composition: centered, stacked, sparse, collage, or full-bleed
- state clearly that the result should look like a designed emotional poster, not an advertisement
Strong prompts for this genre usually answer:
- what is the one emotional point
- what exact words, or near-exact words, should anchor the piece
- what visual field or metaphor surrounds those words
- what aesthetic taste the user would likely find beautiful
Also follow the per-genre aesthetic guide in `{baseDir}/references/image-integration.md`.
## AI Generation Control
Use this section as practical steering guidance for image models.
These words and structures are references and examples, not a rigid whitelist or blacklist. The goal is to improve poster quality without flattening the genre into one fixed house style.
### Core Poster Logic
The strongest emotion posters do not explain feelings literally.
They usually work through:
- one emotional thesis
- one visual metaphor or symbolic field
- one strong text system
- one shared material atmosphere tying image and typography together
To avoid the dead `Canva template` feeling:
- do not overfill the frame
- do not let the text sit on top like an afterthought
- do not make the composition too centered, too balanced, or too obedient
- do not make the picture merely "pretty background plus quote"
An excellent emotion poster usually feels like:
- half image-world
- half typography-world
- both breathing in the same texture
### Poster Modes
Emotion posters can operate in different art-direction modes. Choose the one that best fits the emotional thesis and the user's taste.
`Mode 1: poetic surreal`
- surreal metaphor
- scale distortion
- one impossible but emotionally truthful image
- strong for renewal, grief, longing, hope, or inner threshold moments
`Mode 2: atmospheric literary`
- large negative space
- quiet environment field
- restrained typography
- strong for healing, wistfulness, reflection, night-thought energy
`Mode 3: textured editorial collage`
- mixed media collage
- fragmented paper, painting, or archival material
- typography woven into the surface
- strong for layered thought, historical weight, emotional complexity, or intellectual melancholy
### Magic Words
These are often useful prompt ingredients for this genre. Use them selectively. Do not stuff them in mechanically.
- poster design
- editorial layout
- editorial design
- typography as design element
- visual poetry
- surreal metaphor
- minimalist poster
- large negative space
- cleared space for typography
- off-center composition
- asymmetrical balance
- single focal point
- muted palette
- limited color palette
- mixed media collage
- paper texture
- risograph print
- Riso texture
- film grain
- lo-fi aesthetic
- ambient atmosphere
- ink wash
- faded print texture
- hand-made poster feel
### Poison Words
These words often push the model toward stiff, commercial, or overfilled poster outputs. Avoid them unless you have a very specific reason.
- corporate poster
- standard layout
- symmetrical
- stock photo style
- cluttered background
- text filled
- formal
- PowerPoint aesthetic
- advertisement
- commercial
- sale
- busy
- multiple fonts
- decorative border
- event flyer
- marketing campaign
- brand key visual
### Text Rules
Text is not decoration in this genre. Text is part of the image system.
Always specify:
- the exact wording or near-exact wording
- the font feeling
- the size relative to the frame
- the position
- whether the text is the hero, support, or whisper-level metadata
Useful text directions by aesthetic:
`eastern / traditional / meditative`
- serif with weight or cultural gravity
- calligraphic drift
- seal-like accent
- text can sit with air around it, not packed into rigid blocks
`Y2K / emotional / trend-forward`
- distorted display type
- marker-like handwriting
- acid or glow treatment
- light duplication, shadowing, blur, or liquid-like type behavior when the concept supports it
`literary / healing / intimate`
- warm handwriting
- imperfect hard-pen feeling
- slightly naive or human-feeling lettering
- avoid sterile system-font energy
Do not leave text behavior unspecified. If the model is not told how typography should feel, it often defaults to generic poster text.
### Composition Rules
- preserve large negative space so the text has room to breathe
- keep one clear focal point
- prefer off-center composition or asymmetrical balance over rigid centering
- let the image field support the text instead of competing with it
- avoid filling every corner with objects, fragments, or texture
- make sure the frame still reads as a poster at first glance, not a scene illustration with random text added later
- when using collage, keep it emotionally unified rather than busy for its own sake
### Material And Texture Rules
Pure digital cleanliness often makes this genre feel cheap or generic.
Useful texture directions:
- paper texture
- grain
- faded print softness
- risograph misregistration feel
- watercolor bleed
- ink diffusion
- photocopy roughness
- worn poster surface
The texture should support the emotional thesis. It should not be added as a random "vintage filter."
### Anti-Template Checklist
Before writing the prompt, check:
- is the image expressing the feeling through metaphor rather than just illustrating it literally
- is there enough negative space for text to live comfortably
- is the text system integrated into the same world as the image
- is the composition off-center, asymmetric, or otherwise intentionally designed
- would this still feel personal and artistic rather than commercial if the text were removed
If the answer still feels like `nice background + centered quote`, the prompt needs a stronger visual idea.
### Prompt Template
Use this as a structure, not a fixed incantation:
1. `Emotional thesis`
- state the one emotional point clearly
2. `Poster mode + overall art direction`
- poetic surreal, atmospheric literary, or textured editorial collage
3. `Visual metaphor or image field`
- define the core symbolic scene, object, or field
4. `Composition`
- specify negative space, focal point, and off-center or asymmetrical structure
5. `Typography`
- exact text, font feeling, hierarchy, size, and placement
6. `Material atmosphere`
- paper, grain, Riso, ink, faded print, collage texture, or other shared surface logic
7. `Palette`
- muted, limited, luminous-dark, washed, or otherwise controlled
8. `Exclusions`
- what commercial, rigid, or cluttered tendencies to avoid
Example prompt skeleton:
`[emotional thesis] [poster mode and art direction] [visual metaphor or symbolic image field] [composition with large negative space and focal point] [exact text treatment and typography feeling] [material texture and palette] [what to avoid so it does not look commercial, rigid, or template-like]`
## Aspect Ratio
Prefer:
- `3:4` or `4:5` for most poster compositions
- `9:16` for tall poem-like posters, mobile-native emotional statements, or layouts with strong vertical drift
- `1:1` only when the composition is unusually compact and balanced
The frame should support the line-breaks and visual hierarchy.
## Return Uses
- extending a user's thought or realization
- echoing an emotional state in a more beautiful, legible form
- making a small point feel dignified and memorable
- giving a metaphor enough text support that the user can understand it
- creating a keepsake-like visual artifact around one emotional point
## Failure Modes
Avoid this genre when:
- the concept needs a believable borrowed media shell, in which case `borrowed-media-layout` fits better
- the image is doing nothing and the result becomes just a fancy quote card
- the words are too vague to support a poster
- the composition looks like a brand campaign, event flyer, or product ad
- the poster contains too many different ideas instead of one emotional center
## Reference Assets
If these files are missing locally, fetch bundle `image-examples/emotion-poster` first via `bash {baseDir}/scripts/fetch-asset-bundle.sh "image-examples/emotion-poster"`.
- `assets/examples/image-examples/emotion-poster/ref-01.jpg`
Borrow: luminous illustrative field plus one hand-written emotional line, where the image and words jointly create the poster's center
Avoid copying: exact book-door imagery or quote wording
- `assets/examples/image-examples/emotion-poster/ref-02.jpg`
Borrow: tall poster composition, restrained headline system, and atmosphere-led visual field with typography integrated into the design
Avoid copying: exact "Chinese aesthetics" editorial framing
- `assets/examples/image-examples/emotion-poster/ref-03.jpg`
Borrow: bold hero type over one symbolic central object, making a single concept feel designed and memorable
Avoid copying: exact color palette, title wording, or telephone motif
- `assets/examples/image-examples/emotion-poster/ref-04.jpg`
Borrow: collage-like poster field where text fragments, cultural material, and imagery form one emotional surface
Avoid copying: exact calligraphy scraps, historical imagery, or antique-paper arrangement
FILE:references/image-genres/meme-sticker.md
# Genre: meme-sticker
## Status
Reference-only
## Fit
Use this when the return wants:
- a punchy reaction image
- a sticker-like emotional punchline
- short overlaid text with strong attitude
- humor, teasing, self-mockery, sarcasm, or playful complaint
- a clear contrast between surface behavior and inner feeling
Use this genre when the image should land fast and be funny on first glance rather than requiring slow reading or atmosphere-building.
## Emotional Register
This genre works best when the return is:
- mischievous
- exaggerated
- lightly dramatic
- relatable to ordinary people without needing private lore to decode it
Prefer broad-readable humor over niche cleverness. The user should get the joke quickly, even if the emotional subtext is personal.
## Aspect Ratio
Unlike the default image path, meme-sticker often benefits from shorter frames.
Prefer:
- `1:1` for reaction-image, sticker, and caption-first compositions
- `3:4` for character-with-prop, object gag, or small-scene meme layouts
Use `9:16` only when the joke specifically depends on vertical staging, stacked text beats, or a phone-screen-like composition.
## Subject Strategy
- favor animals, simplified characters, toys, plush-like creatures, objects, or invented non-human mascots over realistic people
- avoid celebrity likenesses, real public figures, or recognizable copyrighted characters
- use one central subject and one emotional action
- let props do narrative work: IV drip, flames, smoke, coffee, trophy, tiny desk, cracked heart, warning sign, hospital bed, etc.
- allow some exaggeration; meme images do not need to be subtle
Small animals, object-characters, and toy-like figures often make the return funnier and less aggressive than a realistic human scene.
## Text Strategy
- keep text short
- make the wording feel native to the user's main interaction language with OpenClaw
- use text as a punchline, label, speech bubble, or deadpan annotation rather than a paragraph
- specify placement deliberately because text position often carries the joke
- make the font feel match the image: blunt meme caption, hand-drawn label, awkward deadpan subtitle, sticker bubble, etc.
Good text use:
- one short headline
- one speech bubble
- one label on a prop
- one contrast pair such as "outside me / inside me"
Avoid:
- long explanation
- dense Chinese text blocks
- text that repeats what the image already says
- elegant typography that kills the joke
## Prompt Strategy
- describe the character, prop, and emotional contradiction concretely
- state the exact type of humor: teasing, ironic, dramatic, burnt-out, fake-motivational, quietly unhinged, etc.
- if there is contrast, name both sides explicitly
- specify whether the frame should feel cheap, cursed, cute, deadpan, overdramatic, or absurdly sincere
- mention practical meme effects when useful: flames, blast glow, motion blur, hospital drip, giant sweat drop, low-budget photo edit energy
- keep the composition easy to read at thumbnail size
The best meme-sticker prompts usually describe one funny scene very clearly instead of piling on many ideas.
Also follow the per-genre aesthetic guide in `{baseDir}/references/image-integration.md`.
## AI Generation Control
Use this section as practical steering guidance for image models.
These words and structures are references and examples, not a rigid whitelist or blacklist. The goal is to improve model behavior without collapsing the genre into a fixed prompt formula.
### Style Tiers
Meme stickers can operate in different style tiers. Choose the tier that best matches the concept rather than defaulting to one visual language every time.
`Tier 1: chaotic / unhinged`
- doodle energy
- sketchy lines
- flat color
- meme reaction image logic
- derp face or blank-stare comedy
- roughness, motion blur, low-budget edit energy
- exaggerated facial expression
`Tier 2: minimal healing`
- chiikawa-like smallness
- minimal line art
- round shapes
- dot eyes, tiny mouth
- soft pastel flat colors
- thick clean outlines
- muted or nearly empty background
`Tier 3: absurd realistic cute`
- photorealistic fur or object texture
- cute creature in human-coded context
- surreal mismatch between subject and situation
- cinematic absurdity, not cinematic beauty
### Magic Words
These are often useful prompt ingredients for this genre. Use them selectively. Do not stuff them in mechanically.
- doodle
- sketch
- simple line art
- flat color
- meme style
- sticker
- reaction image
- deadpan
- derp face
- blank stare
- exaggerated expression
- white background
- solid color background
- thick black outline
- chiikawa-like
- kanahei-like
- rough lines
- low-budget edit energy
### Poison Words
These words often make meme-sticker outputs worse because they push the model toward polished beauty instead of readable humor. Avoid them unless you have a very specific reason.
- masterpiece
- highly detailed
- cinematic lighting
- hyper-realistic
- beautiful
- stunning
- gorgeous
- dramatic atmosphere
- professional photography
- 4K
- 8K
- HDR
### Text Rules
`chaotic / unhinged memes`
- font: bold sans-serif, blunt system-caption energy
- style: white text with black outline, or high-saturation red/yellow
- position: top or bottom, large, obvious, slightly crude is fine
- avoid decorative or artistic font language
`cute / healing memes`
- font: rounded or lightly handwritten is acceptable
- color: pull from the image palette rather than fighting it
- placement: can live in a speech bubble, held sign, or floating label if the scene supports it
### Composition Rules
- optimize for thumbnail readability in a phone chat list
- keep to 2-3 major elements at most
- preserve generous negative space
- let the main character occupy roughly 40-60% of the frame
- avoid complex backgrounds unless the background itself is the joke
- prefer one character plus one prop plus one short text beat over multi-part visual clutter
### Emotional Contrast Checklist
Before writing the prompt, identify:
- the surface emotion: what appears to be happening
- the real emotion: what is actually being felt
- the gap between them: this is often where the humor lives
If surface emotion and real emotion are the same, the meme usually needs a stronger contradiction or a more interesting frame.
### Prompt Template
Use this as a structure, not a fixed incantation:
1. `Style tier + visual language`
- choose one tier and describe the exact drawing or image behavior
2. `Character`
- species or subject, expression, pose, size in frame, one key prop
3. `Scene`
- minimal background type, color, and any one necessary support detail
4. `Humor contrast`
- what makes the image absurd, deadpan, overdramatic, or funny
5. `Text`
- exact wording, language, font feel, color, placement, and relative size
6. `Exclusions`
- what visual tendencies to avoid if they would beautify or overcomplicate the joke
Example prompt skeleton:
`[style tier and style descriptors] [main character/subject] [pose/expression/prop] [minimal scene/background] [humor contrast] [exact on-image text treatment if needed] [what to avoid]`
## Return Uses
- teasing with affection
- turning a repeated frustration into a private in-joke
- making a small emotional truth portable and reusable
- giving the user a funny image they might actually want to save or resend
- returning a complaint in a more lovable, survivable form
## Failure Modes
Avoid this genre when:
- the return needs tenderness more than punch
- the user would likely experience the joke as mocking rather than affectionate
- the image needs long explanatory text to make sense
- the concept depends on elegant atmosphere rather than contrast or punchline
- the humor only works if the model generates precise celebrity likenesses or exact reference characters
## Reference Assets
If these files are missing locally, fetch bundle `image-examples/meme-sticker` first via `bash {baseDir}/scripts/fetch-asset-bundle.sh "image-examples/meme-sticker"`.
- `assets/examples/image-examples/meme-sticker/ref-01.png`
Borrow: simple animal character, deadpan foreground face, absurd background escalation
Avoid copying: exact rabbit design or medical prop setup one-to-one
- `assets/examples/image-examples/meme-sticker/ref-02.png`
Borrow: direct emotion amplification with fire, short text, instant readability
Avoid copying: exact hamster-fire-laptop composition or multilingual text stack
- `assets/examples/image-examples/meme-sticker/ref-03.png`
Borrow: tired small creature plus speech bubble plus tiny prop for social fatigue humor
Avoid copying: exact hat/phone/tea arrangement
- `assets/examples/image-examples/meme-sticker/ref-04.png`
Borrow: exaggerated facial reaction and uncanny visual intensity for disgust/shock
Avoid copying: exact doll face or beauty-doll styling
- `assets/examples/image-examples/meme-sticker/ref-05.png`
Borrow: lo-fi cozy setup with one accessorized animal and one object to define mood
Avoid copying: exact cat-headphones-coffee-bed palette
- `assets/examples/image-examples/meme-sticker/ref-06.png`
Borrow: weird point-of-view framing and unexpected scale relationship for absurd humor
Avoid copying: exact microwave-cat-pizza premise
- `assets/examples/image-examples/meme-sticker/ref-07.png`
Borrow: minimal line-drawn character plus labeled prop for universal exhausted humor
Avoid copying: exact "Coffee / me" wording or bear drawing
FILE:references/video-genres/release-transform.md
# Genre: release-transform
## Status
Reference-only
## Fit
Use this when the return wants:
- something tense, clogged, covered, stuck, or irritating to be released or transformed
- the satisfaction of removal, clearing, extraction, alignment, or reveal
- motion that carries relief, not just atmosphere
- tactile or tool-driven action translated into a watchable cinematic beat
## Core Quality
What makes this genre good is not chaos or destruction alone.
It is good when the viewer can feel a before-state under tension and an after-state with more space, clarity, or relief.
## Motion Strategy
- define the initial tension clearly: clutter, distortion, residue, coating, blockage, knots, pressure, or misalignment
- use one readable transforming action: pull, cut, peel, sweep, vacuum, reveal, straighten, or dissolve
- let the action visibly change the emotional state of the frame
- avoid too many simultaneous tools or mechanics; one satisfying release logic is enough
- if looping, make the loop feel like a ritual cycle rather than a meaningless reset
## Motion Logic References
When the motion grammar overlaps with an H5 pattern, read:
- `pattern-cards/tension-release.md`
- `pattern-cards/burn-reveal.md`
- `pattern-cards/lift-away.md`
- `pattern-cards/tear-stained-paper.md`
- `pattern-cards/wet-letter.md`
Borrow the release logic, tactile timing, and transformation arc.
Do not borrow the original drag or tap mechanics literally.
## Prompt Strategy
- describe the tense first frame in physical terms before describing any release
- if the release depends on a designed surface or abstract system, strongly prefer `i2v-first` so the starting state is visually locked
- name the transforming action and who or what performs it
- describe what changes first, what resists, and what finally yields
- state the tone through visible material change rather than abstract emotion words
- keep the action legible enough that the viewer can understand the metaphor quickly
- prefer one transformation over many decorative secondary motions
Strong prompts in this genre usually answer:
- what is wrong or tense at the start
- what action transforms it
- how the frame looks and feels once relief arrives
- whether the release should feel playful, cleansing, symbolic, or gently absurd
Also follow `{baseDir}/references/video-integration.md`, especially the prompt strategy and MP4 sidecar rules.
## Return Uses
- turning irritation into a watchable ritual of release
- making relief feel tactile and visible
- translating satisfying H5 regulation or reveal patterns into short cinematic clips
- giving the user a tiny symbolic unburdening without requiring interaction
## Reference Assets
- `assets/examples/video-examples/release-transform/`
Keep these lightweight local sidecars in the repo when available
- every `.mp4` example in this folder should have a sibling `.md` file with the same stem describing the starting tension, transforming action, pacing, and what to borrow
FILE:references/video-genres/object-micro-cinema.md
# Genre: object-micro-cinema
## Status
Reference-only
## Fit
Use this when the return wants:
- one object, device, mirror, drawer, shelf, board, cabinet, or keepsake world to hold the meaning
- a cinematic micro-scene centered on opening, approaching, rotating, revealing, or re-reading that object
- objecthood and curation to matter more than pure atmospheric looping
- a short watchable sequence that feels like a tiny film around one meaningful container
## Core Quality
What makes this genre good is not just that an object exists.
It is good when the object behaves like a miniature world: the viewer understands why this object holds the return, and the motion reveals emotional meaning through approach, opening, rearrangement, or reframing.
## Motion Strategy
- establish the object clearly in the first beat
- let camera movement, opening logic, or object transformation reveal meaning step by step
- keep the object as the anchor; supporting particles, light, or labels should serve it
- prefer one short arc: closed to open, distant to intimate, blank to annotated, shelf to keepsake close-up
- if looping, make the object feel revisitable rather than mechanically resetting
## Motion Logic References
When the object logic overlaps with an H5 pattern, read:
- `pattern-cards/memory-shelf.md`
- `pattern-cards/inner-mirror.md`
- `pattern-cards/extension.md`
- `pattern-cards/gifted-data-viz.md`
- `pattern-cards/light-gamification.md` when the object is a countdown box, flip card, or tiny ritual container
Borrow the object grammar, browsing rhythm, reveal timing, and emotional logic of curation.
Do not borrow interactive browsing literally.
## Prompt Strategy
- name the central object first
- lock the first frame before motion: how we first see it, how large it is in frame, and what materials and light define it
- strongly prefer `i2v-first` when the object design, label treatment, or tabletop composition matters
- describe what motion reveals meaning: opening, flipping, zooming, sliding, lighting up, or rearranging
- specify what the object contains or implies, but keep the number of revealed sub-elements curated
- if there is text, labels, or metadata, keep them object-bound so they feel built into the world rather than overlaid
Strong prompts in this genre usually answer:
- what the object is
- why this object is the right container for the thesis
- what the reveal sequence is
- what emotional read the object should leave after the short clip
Also follow `{baseDir}/references/video-integration.md`, especially the H5 bridge guidance and MP4 sidecar rules.
## Return Uses
- turning archive-like H5 ideas into watch-first cinematic keepsakes
- making self-recognition, memory curation, or extension feel like opening a small world
- giving the user one object-centered micro film rather than a scrollable artifact
- returning a thesis through a container that unfolds its meaning
## Reference Assets
- `assets/examples/video-examples/object-micro-cinema/`
Keep these lightweight local sidecars in the repo when available
- every `.mp4` example in this folder should have a sibling `.md` file with the same stem describing the object logic, reveal sequence, pacing, and what to borrow
FILE:references/video-genres/mood-loop.md
# Genre: mood-loop
## Status
Reference-only
## Fit
Use this when the return wants:
- a short atmospheric loop
- subtle repetition with emotional weight
- motion such as wind, rain, glow, drifting dust, or breathing light
- a scene the user should linger inside rather than decode like a story
This is a broad fallback genre.
If a narrower genre such as `atmospheric-surface` or `object-micro-cinema` fits more precisely, prefer the narrower one first.
## Core Quality
What makes this genre good is not event density but atmospheric persistence.
The loop should feel intentional enough that the user wants to stay with it, not merely notice that it repeats.
## Motion Strategy
- keep the clip short and loop-friendly
- let one or two motions carry the feeling
- prefer mood evolution over narrative complexity
- make the loop seam hard to notice
- choose motions that can sustain emotional pressure through repetition: drifting curtain, rain on glass, breathing neon, slowly moving foliage, ash, glow, dust, water shimmer
## Motion Logic References
When the movement grammar overlaps with an H5 pattern, read that pattern card for emotional pacing and directional logic:
- `rainy-night.md`
- `wet-letter.md`
- `tear-stained-paper.md`
- `kinetic-collage.md`
- `memory-shelf.md`
- `extension.md`
Borrow the motion logic, not the interaction.
## Prompt Strategy
- describe the loop length clearly, usually `4` to `8` seconds
- lock the first frame first so the loop already feels complete before anything moves
- strongly prefer `i2v-first` when palette, texture, weather, or light behavior are central to the loop
- state what motion exists at the beginning so the first frame is not empty
- specify what tiny change happens over time and how the loop closes
- describe texture and light behavior, not just scene objects
- if using a symbol, make it emerge naturally from the atmosphere rather than as a pasted metaphor
- avoid overplotting; one breathing motion and one supporting motion are usually enough
Strong prompts in this genre usually answer:
- what the viewer is looking at
- what one or two motions keep the scene alive
- how the light, weather, or particles behave
- what emotional aftertaste the loop should leave
Also follow `{baseDir}/references/video-integration.md`, especially the genre bridge and MP4 sidecar rules.
## Return Uses
- returning a feeling that needs time rather than explanation
- giving the user a place to linger inside the mood
- turning atmosphere itself into the gift
## Reference Assets
- `assets/examples/video-examples/mood-loop/`
Keep these lightweight local sidecars in the repo when available
- every `.mp4` example in this folder should have a sibling `.md` file with the same stem describing motion logic, pacing, loop behavior, and what to borrow
FILE:references/video-genres/kinetic-text.md
# Genre: kinetic-text
## Status
Reference-only
## Fit
Use this when the return wants:
- text itself to be the moving subject
- motion-graphics-like language instead of a physical scene
- readable words or glyph fragments to carry the emotional turn
- release, flow, lift, dissolve, reveal, or drift to happen through text motion
## Core Quality
What makes this genre good is not just that text moves.
It is good when the movement grammar itself expresses the return: release, continuation, accumulation, disturbance, disappearance, or reformation.
## Motion Strategy
- keep the clip short enough that the motion arc stays legible, often `4` to `8` seconds
- make the first frame compositionally strong before anything moves
- choose one dominant motion logic: scatter, flow, lift, reveal, dissolve, or erosion
- make text movement readable enough to feel intentional, even when full paragraph reading is not the point
- if the clip loops, ensure the end state can reconnect gracefully to the beginning
## Motion Logic References
When the motion matches an existing H5 pattern, read that pattern card for motion grammar and pacing:
- text scattering outward -> `pattern-cards/wind-scatter.md`
- text flowing like a current -> `pattern-cards/text-river.md`
- elements lifting away -> `pattern-cards/lift-away.md`
- surface burning or clearing to reveal a lower layer -> `pattern-cards/burn-reveal.md`
- wet or disturbed text surfaces -> `pattern-cards/wet-letter.md`
- fragile distressed text motion -> `pattern-cards/tear-stained-paper.md`
Borrow the motion logic, timing, direction, rhythm, and emotional arc of the movement.
Do not borrow the code or interaction design.
Video does not need interaction. The motion itself is the experience.
## Prompt Strategy
- treat this as Mode B by default: lock a strong first frame, then describe only the motion
- strongly prefer `i2v-first` so the text block, background texture, and composition are anchored before animation begins
- specify duration clearly
- describe the exact text form, size, position, color, and background in frame `0`
- describe exactly when and how the motion begins
- describe what happens in the middle beat
- describe what remains, dissolves, or resolves at the end
- keep the background and non-text elements restrained unless they truly support the motion
Strong prompts in this genre usually answer:
- what text or text-like form appears first
- what motion logic transforms it
- what the motion means emotionally
- what the final visual state should feel like
Also follow `{baseDir}/references/video-integration.md`, especially the prompt strategy and MP4 sidecar rules.
## Return Uses
- turning one line into a cinematic release
- making thought, memory, or language itself become the moving gift
- translating strong H5 text motion ideas into a watch-first format
- returning a line of language through pacing and motion rather than interaction
## Reference Assets
- `assets/examples/video-examples/kinetic-text/`
Keep these lightweight local sidecars in the repo when available
- every `.mp4` example in this folder should have a sibling `.md` file with the same stem describing timing, motion grammar, pacing, loop behavior, and what to borrow
FILE:references/video-genres/scene-animation.md
# Genre: scene-animation
## Status
Reference-only
## Fit
Use this when the return wants:
- a short animated scene
- visible progression inside one location
- motion that changes the meaning of the scene
- a cinematic micro-arc rather than a pure ambient loop
This is a broad fallback genre.
If a narrower genre such as `touch-awakening`, `release-transform`, or `object-micro-cinema` fits more precisely, prefer the narrower one first.
## Core Quality
What makes this genre good is not just that something moves, but that the order of movement creates meaning.
The viewer should feel that the scene changes because of the motion, not that motion was added afterward for polish.
## Motion Strategy
- define what moves first, what follows, and what settles
- keep the action readable in a few seconds
- make sure the movement is carrying the return, not just adding polish
- prefer one readable progression over many simultaneous events
- if a reveal or bloom happens, stage it so the viewer can actually feel the before and after
## Motion Logic References
When the motion logic already exists in an H5 pattern, read the relevant card first:
- `tap-to-bloom.md`
- `rainy-night.md`
- `tension-release.md`
- `light-gamification.md`
- `inner-mirror.md`
- `gifted-data-viz.md`
Borrow the motion grammar and emotional sequence, not the interaction design.
## Prompt Strategy
- describe visible states and motion precisely rather than relying on abstract idea words
- lock the first frame before describing the scene progression
- prefer `i2v-first` when the scene layout, character treatment, or lighting setup matters to the arc
- specify duration and whether it should loop cleanly or end on a resolved final frame
- describe the initial state, the transition, and the settled or revealed state
- state what movement is emotionally central: bloom, pull, reveal, release, turn, glow shift, collapse, or environmental change
- if text appears, keep it secondary unless the whole video is fundamentally kinetic text
Strong prompts in this genre usually answer:
- what the viewer sees first
- what changes second
- what the emotional turn is
- what the final visual state should feel like
Also follow `{baseDir}/references/video-integration.md`, especially the H5-vs-video guidance and MP4 sidecar rules.
## Return Uses
- showing a small emotional arc
- giving the anchor a cinematic reveal
- making a setting feel alive enough to return a new perspective
## Reference Assets
- `assets/examples/video-examples/scene-animation/`
Keep these lightweight local sidecars in the repo when available
- every `.mp4` example in this folder should have a sibling `.md` file with the same stem describing motion logic, progression beats, loop or non-loop behavior, and what to borrow
FILE:references/video-genres/touch-awakening.md
# Genre: touch-awakening
## Status
Reference-only
## Fit
Use this when the return wants:
- a local trigger point that awakens the surrounding world
- blooming, revealing, warming, or activating motion that spreads outward
- the emotional logic of `attention causes life`
- interaction-like energy translated into a watch-first cinematic form
## Core Quality
What makes this genre good is not literal tapping.
It is good when one point of contact causes a believable, emotionally satisfying field change: bloom, glow, reveal, color shift, growth, or awakening.
## Motion Strategy
- start from a scene or surface that feels dormant, quiet, or not-yet-awake
- introduce one clear trigger source: wand, raindrop, light point, footstep, hand, floating charm, or creature
- let the activation spread visibly from a local point rather than happening everywhere at once
- keep the expansion readable; one touched area waking the next is stronger than instant full-screen change
- if looping, make the end state reconnect naturally to the quiet initial state
## Motion Logic References
When the movement grammar overlaps with an H5 pattern, read:
- `pattern-cards/tap-to-bloom.md`
- `pattern-cards/rainy-night.md`
- `pattern-cards/inner-mirror.md`
- `pattern-cards/extension.md`
- `pattern-cards/light-gamification.md` for countdown or charm-triggered reveal energy
Borrow the trigger logic, spread rhythm, and emotional arc.
Do not borrow the original interaction requirement literally.
## Prompt Strategy
- describe the first frame first: what is dormant, where it sits, and what the viewer sees before activation
- if the visual system is stylized, particle-led, or abstract, strongly prefer `i2v-first` so the sleeping state is anchored before motion begins
- name the trigger source clearly
- describe how the touched zone changes and how that change spreads
- specify whether the motion should feel magical, botanical, luminous, watery, celestial, or quietly technological through visible effects rather than abstract feeling words
- if the scene includes a character, that character should function as the trigger or witness, not as a generic centerpiece
- keep the visual system focused on one awakening logic rather than multiple simultaneous effect families
Strong prompts in this genre usually answer:
- what is asleep or latent at the start
- what touches or activates it
- how the activation spreads
- what the awakened state feels like emotionally
Also follow `{baseDir}/references/video-integration.md`, especially the H5-vs-video guidance and MP4 sidecar rules.
## Return Uses
- turning a hopeful line into a visibly awakened world
- making encouragement feel active rather than declarative
- translating touch-driven H5 joy into a more cinematic magical reveal
- showing that life, warmth, or attention can spread from one small act
## Reference Assets
- `assets/examples/video-examples/touch-awakening/`
Keep these lightweight local sidecars in the repo when available
- every `.mp4` example in this folder should have a sibling `.md` file with the same stem describing trigger source, spread rhythm, pacing, and what to borrow
FILE:references/video-genres/relatable-surrealism.md
# Genre: relatable-surrealism
## Status
Reference-only
## Fit
Use this when the return wants:
- a highly relatable modern emotion, complaint, craving, or social type visualized through a small surreal scene
- daily life turned into a metaphorical skit, proxy creature moment, or dimensional mismatch
- funny, tired, i-person, weekend, gossip, work, commute, or homebody feelings to become instantly legible
- emotional recognition through exaggeration rather than through literal realism
## Core Quality
What makes this genre good is not randomness or absurdity alone.
It is good when a very ordinary feeling becomes newly visible through one concise surreal device: an animal stand-in, a desk turned into a road, a flat-lay life turned into a side-scroller, or a single symbolic action that says "yes, this is exactly what that mood feels like."
The best versions feel socially recognizable, emotionally precise, and visually playful at the same time.
## Motion Strategy
- choose one daily-life emotional thesis first: overworked, socially drained, weekend-liberated, gossiping, staying in bed, craving snacks, and so on
- choose one surreal device that expresses that thesis fast: animal proxy, scale mismatch, 2D world, desk-road, exaggerated collapse, UI obstacles, or one symbolic dance
- keep the action symbolic and readable, not over-choreographed
- use a few representative beats rather than a long dense story
- let motion exaggerate the emotional logic: frantic typing, collapsing, sliding, bouncing, gossip-mouth loop, delighted tail-wag reaction
- if looping, make the loop feel like a memeable situation or repeating life pattern
## Motion Logic References
When the movement grammar overlaps with an H5 pattern, read:
- `pattern-cards/light-gamification.md` for symbolic task loops, countdown logic, and tiny legible frames
- `pattern-cards/inner-mirror.md` when a proxy creature or stylized scene is really a mirror of the user
- `pattern-cards/extension.md` when the gift lightly extends a shared complaint or social observation
- `pattern-cards/tension-release.md` when the surreal action is really a regulation or release metaphor
- `pattern-cards/kinetic-collage.md` when the scene is built from flat-lay composition and one or two moving accents
Borrow the emotional shorthand, symbolic action, and pacing discipline.
Do not borrow interaction mechanics literally.
## Prompt Strategy
- describe the visible frame first rather than the social thesis in abstract words
- if the surreal setup depends on a specific scene, prop set, or proxy character design, prefer `i2v-first` to lock the world before motion starts
- name the surreal device that translates the feeling
- state the camera logic clearly: top-down desk, flat-lay carpet, white studio backdrop, office workstation, bed-level phone view, and so on
- describe only the representative actions that carry the joke or feeling
- if using an animal proxy, make the social role and props very clear
- if using a flat-lay or top-down illusion, keep perspective rules strict
- if using text, keep it short and meme-legible
Strong prompts in this genre usually answer:
- what ordinary emotion or social type is being visualized
- what stand-in or world-shift makes it funny or vivid
- what one to three actions make the feeling legible
- what overall tone the clip should leave: commiserating, cathartic, delighted, dead-tired, socially seen
Also follow `{baseDir}/references/video-integration.md`, especially the MP4 sidecar rules and prompt strategy guidance.
## Return Uses
- turning common modern feelings into compact watchable metaphors
- making the user feel "this is exactly my life" through a playful surreal proxy
- returning a complaint, stereotype, or social feeling with affection instead of heaviness
- producing memeable but emotionally accurate short-form video gifts
## Aesthetic Principles
- emotional accuracy matters more than technical complexity
- one strong metaphor beats three weak ones
- lo-fi stop-motion roughness can help if it strengthens charm and reduces heaviness
- props, UI fragments, and physical contact points should still obey the chosen perspective and lighting logic
- proxy creatures should be cute or vivid enough to create contrast, but not so generic that they lose the specific feeling
## Suitable Emotional Register
Strong fits:
- work fatigue
- social exhaustion
- gossip energy
- weekend euphoria
- lazy-at-home softness
- low-stakes complaint humor
- "this is so me" recognition
Usually weaker fits:
- solemn grief
- subtle poetic atmosphere with no social or behavioral hook
- deeply private emotional material that would feel trivialized by exaggeration
- abstract philosophical reflection with no situation anchor
## Example Motif Families
- animal stand-in for social role or mood
- tiny surreal office or commute scene
- flat-lay lifestyle stage where the person slides or swaps states
- tabletop world that turns tasks or messages into physical obstacles
- one exaggerated micro-performance that captures a shift in mood
## Reference Assets
- `assets/examples/video-examples/relatable-surrealism/`
Fetch first if missing: `bash {baseDir}/scripts/fetch-asset-bundle.sh "video-examples/relatable-surrealism"`
- every `.mp4` example in this folder should have a sibling `.md` file with the same stem describing the ordinary emotion, surreal device, representative actions, perspective logic, and what to borrow
FILE:references/video-genres/atmospheric-surface.md
# Genre: atmospheric-surface
## Status
Reference-only
## Fit
Use this when the return wants:
- the emotional meaning to live in surfaces, weather, reflections, condensation, paper, glass, water, dust, or light
- the viewer to feel they are watching a way of seeing rather than a scene plot
- indirect observation to carry the beauty
- a short video that breathes through material change rather than event beats
## Core Quality
What makes this genre good is not action density.
It is good when the surface itself becomes expressive: water distorts, glass beads, ink spreads, fog clears, paper absorbs, light scatters, or reflections tremble.
## Motion Strategy
- choose one surface family as the emotional anchor: glass, water, paper, mist, stone, mirror, screen, or wet ground
- let the viewer read the movement through texture and light behavior
- keep motion delicate but legible; small changes should still feel intentional
- avoid adding unnecessary characters or props when the surface itself can carry the feeling
- if looping, make the texture cycle feel natural, like weather or breath, not mechanical
## Motion Logic References
When the motion grammar overlaps with an H5 pattern, read:
- `pattern-cards/rainy-night.md`
- `pattern-cards/wet-letter.md`
- `pattern-cards/tear-stained-paper.md`
- `pattern-cards/text-river.md`
Borrow the way those patterns use surfaces, disturbance, and atmospheric change.
Do not borrow the original interaction requirement.
## Prompt Strategy
- describe the first frame surface first, including texture, camera distance, and where the light sits
- strongly prefer `i2v-first` when the exact surface, palette, or condensation pattern matters
- describe what the surface is doing over time
- specify how light behaves on or through that surface
- keep the frame observational rather than symbolic by default
- if a human presence appears, prefer silhouette, reflection, shadow, or fragment rather than a full visible figure
- let material behavior do the emotional work before adding extra narrative objects
Strong prompts in this genre usually answer:
- what surface we are watching
- what subtle motion changes that surface
- how the light behaves
- what emotional atmosphere the surface returns
Also follow `{baseDir}/references/video-integration.md`, especially the H5 bridge guidance and MP4 sidecar rules.
## Return Uses
- returning rain, distance, tenderness, or afterglow through textures rather than plot
- making indirect observation itself into the gift
- translating atmospheric H5 surface patterns into watch-first cinema
- letting material behavior carry emotion without overexplaining it
## Reference Assets
- `assets/examples/video-examples/atmospheric-surface/`
Keep these lightweight local sidecars in the repo when available
- every `.mp4` example in this folder should have a sibling `.md` file with the same stem describing surface choice, material behavior, light behavior, pacing, and what to borrow
FILE:references/video-genres/live-scene-doodle.md
# Genre: live-scene-doodle
## Status
Reference-only
## Fit
Use this when the return wants:
- a real photographed or filmed scene as the emotional base
- simple hand-drawn 2D doodles, text, stars, particles, clouds, fireworks, seeds, or icons layered on top
- a strong contrast between high-fidelity reality and naive, childlike, magical motion
- one quiet real-world anchor made more alive through a small impossible event
## Core Quality
What makes this genre good is not simply adding doodles to footage.
It is good when the doodles feel emotionally and physically attached to the scene: a cup can receive rain, a flower can orbit text, a page can emit stars, a foam top can bloom into fireworks.
The best versions feel like `reality with one illustrated secret`.
## Motion Strategy
- start from one visually strong real-world anchor: cup rim, flower center, book page, window edge, tabletop, foam surface, horizon line
- add only one doodle family or one main metaphor per clip
- keep the doodle motion loop short, light, and repeatable: drift, drip, orbit, burst, float, trail, scatter
- align doodle start and end points precisely to the real object's boundary
- use empty sky, wall, table, or dark negative space as breathing room for the doodle layer
- let the real footage stay calm; the doodle should animate the scene, not fight it
## Motion Logic References
When the motion grammar overlaps with an H5 pattern, read:
- `pattern-cards/tap-to-bloom.md` for local awakening and delight
- `pattern-cards/rainy-night.md` for atmospheric observation on real surfaces
- `pattern-cards/wind-scatter.md` for floating seeds, fragments, or doodled drift
- `pattern-cards/kinetic-collage.md` for visual layering and editorial taste
- `pattern-cards/light-gamification.md` when the doodle behaves like a tiny celebratory reward effect
Borrow the metaphor logic, attachment logic, and emotional pacing.
Do not borrow literal interaction mechanics or template composition.
## Prompt Strategy
- treat this as scene-first Mode A: describe the real frame before the doodle logic
- prefer `i2v-first` when the photographed scene, camera framing, or lighting treatment matters
- describe the real scene first with camera framing, material, light, and anchor object
- then describe the doodle layer in very simple visual language: white line cloud, pastel handwritten word, small glowing star, fluorescent line fireworks
- specify exactly where the doodle is attached to the scene
- describe the loop behavior in one short readable cycle
- state the emotional contrast through visible scene-plus-doodle contrast rather than abstract mood words
- keep the doodles minimal and stylized; avoid turning them into full 3D effects or highly rendered illustrations
Strong prompts in this genre usually answer:
- what the real-world anchor is
- what impossible doodle metaphor appears around it
- where the doodle is physically attached
- what tiny repeating motion carries the return
Also follow `{baseDir}/references/video-integration.md`, especially the MP4 sidecar rules and H5-vs-video guidance.
## Return Uses
- turning a quiet real-world shot into a tiny emotional fairytale
- making one object feel more alive, lonely, celebratory, or dreamlike through a simple overlay metaphor
- returning healing, wonder, or soft melancholy without building a full narrative sequence
- using real-scene texture plus minimal doodle motion to create a strong aesthetic identity quickly
## Aesthetic Principles
- realism plus childish doodle contrast is the point
- doodles should be simple enough that their emotional meaning lands instantly
- the real footage should still be beautiful without the doodle layer
- leave breathing room; clean backgrounds help the overlay feel precious
- match doodle brightness and palette to ambient light: pure white or soft neon in darker shots, brighter colored accents in clearer brighter shots
## Suitable Emotional Register
Strong fits:
- healing
- dreamy tenderness
- quiet loneliness
- micro-celebration
- gentle wonder
- poetic smallness
Usually weaker fits:
- dense exposition
- multi-step narrative comedy
- aggressive catharsis
- scenes that need heavy world-building rather than one elegant metaphor
## Example Motif Families
- handwritten orbit words around a flower or hand
- stars, sparks, or small celestial objects flying out of a book or window
- clouds, rain, tears, or tiny weather systems attached to a drink, lamp, or object
- fireworks, glow bursts, or celebratory line blooms from foam, fruit, lights, or rooftops
- seeds, petals, birds, or particles drifting across large real landscapes
## Reference Assets
- `assets/examples/video-examples/live-scene-doodle/`
Fetch first if missing: `bash {baseDir}/scripts/fetch-asset-bundle.sh "video-examples/live-scene-doodle"`
- every `.mp4` example in this folder should have a sibling `.md` file with the same stem describing the real anchor, doodle attachment point, loop behavior, and what to borrow