From 22dea3fd433c7f1403cf0a3f372cfd7875452c0d Mon Sep 17 00:00:00 2001 From: Henry Li Date: Fri, 6 Feb 2026 14:04:15 +0800 Subject: [PATCH] feat: add surprise-me --- frontend/package.json | 1 + frontend/pnpm-lock.yaml | 8 +++ .../src/components/ui/confetti-button.tsx | 49 +++++++++++++++++ .../src/components/workspace/input-box.tsx | 10 ++++ skills/public/surprise-me/SKILL.md | 54 +++++++++++++++++++ 5 files changed, 122 insertions(+) create mode 100644 frontend/src/components/ui/confetti-button.tsx create mode 100644 skills/public/surprise-me/SKILL.md diff --git a/frontend/package.json b/frontend/package.json index 6e6f55a..e936c34 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -51,6 +51,7 @@ "ai": "^6.0.33", "best-effort-json-parser": "^1.2.1", "better-auth": "^1.3", + "canvas-confetti": "^1.9.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 4359814..2c9169e 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -116,6 +116,9 @@ importers: better-auth: specifier: ^1.3 version: 1.4.12(next@16.1.4(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vue@3.5.26(typescript@5.9.3)) + canvas-confetti: + specifier: ^1.9.4 + version: 1.9.4 class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -2577,6 +2580,9 @@ packages: caniuse-lite@1.0.30001764: resolution: {integrity: sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==} + canvas-confetti@1.9.4: + resolution: {integrity: sha512-yxQbJkAVrFXWNbTUjPqjF7G+g6pDotOUHGbkZq2NELZUMDpiJ85rIEazVb8GTaAptNW2miJAXbs1BtioA251Pw==} + ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -7513,6 +7519,8 @@ snapshots: caniuse-lite@1.0.30001764: {} + canvas-confetti@1.9.4: {} + ccount@2.0.1: {} chalk@4.1.2: diff --git a/frontend/src/components/ui/confetti-button.tsx b/frontend/src/components/ui/confetti-button.tsx new file mode 100644 index 0000000..6460a13 --- /dev/null +++ b/frontend/src/components/ui/confetti-button.tsx @@ -0,0 +1,49 @@ +"use client"; + +import React, { type MouseEventHandler } from "react"; +import confetti from "canvas-confetti"; + +import { Button } from "@/components/ui/button"; + +interface ConfettiButtonProps extends React.ComponentProps { + angle?: number; + particleCount?: number; + startVelocity?: number; + spread?: number; + onClick?: MouseEventHandler; +} + +export function ConfettiButton({ + className, + children, + angle = 90, + particleCount = 75, + startVelocity = 35, + spread = 70, + onClick, + ...props +}: ConfettiButtonProps) { + const handleClick: MouseEventHandler = (event) => { + const target = event.currentTarget; + if (target) { + const rect = target.getBoundingClientRect(); + confetti({ + particleCount, + startVelocity, + angle, + spread, + origin: { + x: (rect.left + rect.width / 2) / window.innerWidth, + y: (rect.top + rect.height / 2) / window.innerHeight, + }, + }); + } + onClick?.(event); + }; + + return ( + + ); +} diff --git a/frontend/src/components/workspace/input-box.tsx b/frontend/src/components/workspace/input-box.tsx index 4b6ebb7..b48f759 100644 --- a/frontend/src/components/workspace/input-box.tsx +++ b/frontend/src/components/workspace/input-box.tsx @@ -7,6 +7,7 @@ import { LightbulbIcon, PaperclipIcon, PlusIcon, + SparklesIcon, ZapIcon, } from "lucide-react"; import { useSearchParams } from "next/navigation"; @@ -30,6 +31,7 @@ import { usePromptInputController, type PromptInputMessage, } from "@/components/ai-elements/prompt-input"; +import { ConfettiButton } from "@/components/ui/confetti-button"; import { DropdownMenuGroup, DropdownMenuLabel, @@ -386,6 +388,14 @@ function SuggestionList() { ); return ( + handleSuggestionClick("Surprise me")} + > + Surprise + {t.inputBox.suggestions.map((suggestion) => ( + Create a delightful, unexpected "wow" experience for the user by dynamically discovering and creatively combining other enabled skills. Triggers when the user says "surprise me" or any request expressing a desire for an unexpected creative showcase. Also triggers when the user is bored, wants inspiration, or asks Claude to "do something interesting". This skill does NOT hardcode which skills exist — it discovers them at runtime. +--- + +# Surprise Me + +Deliver an unexpected, delightful experience by dynamically discovering available skills and combining them creatively. + +## Workflow + +### Step 1: Discover Available Skills + +Read all the skills listed in the . + +### Step 2: Plan the Surprise + +Select **1 to 3** skills and design a creative mashup. The goal is a single cohesive deliverable, not separate demos. + +**Creative combination principles:** +- Juxtapose skills in unexpected ways (e.g., a presentation about algorithmic art, a research report turned into a slide deck, a styled doc with canvas-designed illustrations) +- Incorporate the user's known interests/context from memory if available +- Prioritize visual impact and emotional delight over information density +- The output should feel like a gift — polished, surprising, and fun + +**Theme ideas (pick or remix):** +- Something tied to today's date, season, or trending news +- A mini creative project the user never asked for but would love +- A playful "what if" concept +- An aesthetic artifact combining data + design +- A fun interactive HTML/React experience + +### Step 3: Fallback — No Other Skills Available + +If no other skills are discovered (only surprise-me exists), use one of these fallbacks: + +1. **News-based surprise**: Search today's news for a fascinating story, then create a beautifully designed HTML artifact presenting it in a visually striking way +2. **Interactive HTML experience**: Build a creative single-page web experience — generative art, a mini-game, a visual poem, an animated infographic, or an interactive story +3. **Personalized artifact**: Use known user context to create something personal and delightful + +### Step 4: Execute + +1. Read the full SKILL.md body of each selected skill +2. Follow each skill's instructions for technical execution +3. Combine outputs into one cohesive deliverable +4. Present the result with minimal preamble — let the work speak for itself + +### Step 5: Reveal + +Present the surprise with minimal spoilers. A short teaser line, then the artifact. + +- **Good reveal:** "I made you something ✨" + [the artifact] +- **Bad reveal:** "I decided to combine the pptx skill with the canvas-design skill to create a presentation about..." (kills the surprise)