SkillAtlasSkill 详情

cast

The art of illusion. Cast motion. Paint signatures.

审核状态:已审核Quality 72Security 70

复制安装命令

用 Codex 或 Claude 安装复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它先审查 Skill 页面再帮你安装。

复制前请先查看来源、License 和安全提示。

项目 README

来源文件:README.md

抓取于 2026年8月13日

genjutsu logo

genjutsu

The art of illusion. Cast motion. Paint signatures.

Website  ·  Documentation  ·  Install

Latest release MIT license Works with Claude Code, claude.ai and Cowork

Creative coding skills for Claude Code, claude.ai and Cowork - transforms any interface from functional to exceptional through motion design, interaction patterns, and visual systems. Covers Web (React, Vue, Svelte, vanilla CSS, Three.js, Canvas), Android (Jetpack Compose, Compose Multiplatform), and Apple (SwiftUI iOS + macOS).

v3.0 - rebrand: this plugin used to be called creative-excellence. The skills /creative-excellence:creative-excellence and /creative-excellence:design-excellence are now /genjutsu:cast and /genjutsu:paint. See CHANGELOG.md for the migration steps if you had v2.x installed.


Documentation

genjutsu.athevon.dev is built with genjutsu itself. The ink on it is painted by your own scroll, and every mark is drawn in code, no image assets.

PageWhat is in it
OverviewWhat genjutsu is, how the pieces fit, the shortest path to seeing something move
InstallBoth surfaces, verifying the install, updating, uninstalling
castThe seven-stage pipeline, its two validation gates, how to write a good request
paintThe five phases, the two theses, what lands in your repo
ModulesAll fifteen, by family: foundations, web, Apple, Android
PrinciplesThe rules the skills enforce, and why each one exists
FAQPlans, dependencies, cast against paint, what to check when output feels generic

Skills

/genjutsu:cast - The Illusionist

Takes any creative request and makes it exceptional. Adapts to your stack and scope.

Pipeline: Scan stack -> Evaluate scope -> Propose interaction thesis -> Load sub-skills -> Implement -> Mini-audit

  • Detects your dependencies automatically across web (GSAP, Framer Motion, Three.js, CSS), Android (Jetpack Compose, Compose Multiplatform) and Apple (SwiftUI iOS / macOS)
  • Proposes an interaction thesis before writing a single line of code, and asks how you want to see it first
  • Scales from a single hover effect to a full scroll-driven page or a Compose SharedTransitionLayout flow
  • Runs a quick audit on exit: reduced-motion, exit animations, recomposition, hitches, layout performance

/genjutsu:paint - The Master Painter

Builds a complete visual universe from scratch. Brainstorm first, implement second.

Pipeline: Brainstorm -> Define visual + interaction thesis -> Generate design system -> Implement -> Full audit

  • Mandatory creative direction session before any code
  • Shows the theses and the design system in the format you pick, instead of asking you to approve a palette as a list of hex codes
  • Generates a persistent stack-aware MASTER.md design system (Tailwind/CSS for web, Theme.kt for Compose, Color+App.swift for SwiftUI, commonMain for CMP)
  • Full audit at the end: motion gaps, accessibility, color consistency, responsive, performance, native hitches
  • Optional MCP integration (Stitch, Nano Banana, 21st.dev Magic)

When to use which

SituationSkill
"Add a scroll animation to this section"/genjutsu:cast
"Make this dropdown feel snappy"/genjutsu:cast
"Add a snappy spring to this Compose button"/genjutsu:cast
"Polish the matchedGeometryEffect on this SwiftUI screen"/genjutsu:cast
"Redesign the entire landing page"/genjutsu:paint
"Build me a portfolio from scratch"/genjutsu:paint
"Build a SwiftUI iOS app design system from scratch"/genjutsu:paint
"Bootstrap a Compose Multiplatform design system"/genjutsu:paint

Seeing what it proposes

Both skills stop and wait for your approval at a handful of points: the interaction thesis, the variants, the visual identity, the design system. A sentence cannot carry an easing curve and a list of hex codes cannot carry a palette, so before the first of those gates the skill asks how you want to see it.

ModeWhat you get
ArtifactA live page. The easing curve plotted with its exact value, an element actually performing the motion with a replay button, the raw numbers, a reduced-motion toggle. For a design system: swatches with their contrast ratios, a real type specimen, the five states of every component.
Live previewA throwaway route in your own project - real stack, real tokens, real components. On Compose or SwiftUI, a @Preview / #Preview scratch file. Deleted once you have approved.
InlineThe sentence, in the conversation. Still the right answer for a 150ms hover.

You are asked once. The choice holds for the rest of the session, later gates just announce the mode, and you switch by saying so. The preview is always throwaway: it exists to be looked at, never to become the implementation.


Sub-skills

Internal modules loaded dynamically by the orchestrators. Not invocable directly.

Foundation (always loaded)

Sub-skillScopeFiles
motion-principlesTiming, easing, cross-platform reduced-motion API, BAD/GOOD do-not rulesSKILL + 3 references

Shared layers (loaded by context)

Sub-skillScopeFiles
mobile-principlesTouch targets, no-hover doctrine, thumb zones, safe areas, gestures, mobile perf budgetsSKILL + 2 references
desktop-principlesHover-mandatory, pointer precision, keyboard shortcuts, multi-window, focus managementSKILL + 2 references
design-auditMulti-stack greps (web/Compose/SwiftUI), bundle size, Layout Inspector, Instruments HitchesSKILL
ui-ux-pro-maxDesign system intelligence (84 styles, 192 palettes, 74 font pairings, 25 charts, 22 stacks)SKILL + data + scripts

Web stack

Sub-skillScopeFiles
gsapCore, timeline, ScrollTrigger, pluginsSKILL + 4 references
framer-motionAnimatePresence, layout, gestures, motion valuesSKILL + 1 reference
css-nativeScroll-driven, View Transitions, @starting-styleSKILL + 1 reference
threejs-r3fThree.js, React Three Fiber, shaders, postprocessingSKILL + 2 references
canvas-generativeParticles, flow fields, noise, fractals, L-systemsSKILL + 1 reference

Android stack

Sub-skillScopeFiles
compose-motionanimate*AsState, AnimatedVisibility, SharedTransitionLayout, springs, gesturesSKILL + 3 references
compose-graphicsM3 Expressive motion physics, AGSL shaders (Android 13+), Canvas/DrawScopeSKILL + 3 references
compose-multiplatformKMP/CMP patterns, expect/actual, iOS/Android/Desktop interopSKILL + 2 references

Apple stack

Sub-skillScopeFiles
swiftui-motionwithAnimation, transitions, matchedGeometryEffect, PhaseAnimator, KeyframeAnimator, gesturesSKILL + 3 references
swiftui-graphicsMetal shaders (.colorEffect / .layerEffect / .distortionEffect), .visualEffect, Liquid Glass (iOS 26), CanvasSKILL + 3 references

Installation

The short version is on the site: genjutsu.athevon.dev/docs/install. The long version, including partial installs, is below.

claude.ai (web/app)

Prerequisites: Plan Pro, Max, Team or Enterprise with "Code execution" enabled.

Option A - single bundle (recommended):

One upload, everything included (router + cast + paint + all sub-skills).

  1. Download genjutsu.zip. That link always serves the newest release, so it never goes stale.
  2. On claude.ai, go to Customize > Skills > Upload skill and upload genjutsu.zip.
  3. Enable the toggle. Done - one skill, both cast and paint pipelines, all sub-skills bundled.

Want to confirm it mounted correctly? Follow the 2-minute smoke test in docs/claude-ai-testing.md.

How it shows up. The bundle installs as a single skill named genjutsu. In a normal chat it appears as one entry - invoke /genjutsu (or just describe your task) and it routes to the cast or paint pipeline internally. Surfaces that expose skills as individual commands (e.g. a code workspace) show /cast and /paint directly. Either way the pipelines need code execution enabled to load their sub-skills. Prefer /cast and /paint as separate entries everywhere? Use Option B.

Option B - individual skills:

Prefer separate skills, or only part of the stack? Upload the individual ZIPs (one per skill). Baseline for everyone: cast, paint, motion-principles, design-audit, ui-ux-pro-max. Then add per stack:

Your stackZIPs to upload (in addition to baseline)
Web onlymobile-principles, desktop-principles, gsap, framer-motion, css-native, threejs-r3f, canvas-generative
Android Compose onlymobile-principles, compose-motion, compose-graphics
iOS SwiftUI onlymobile-principles, swiftui-motion, swiftui-graphics
macOS SwiftUI onlydesktop-principles, swiftui-motion, swiftui-graphics
Multi-target Apple (iOS + macOS)mobile-principles, desktop-principles, swiftui-motion, swiftui-graphics
Compose Multiplatformmobile-principles, compose-motion, compose-graphics, compose-multiplatform, swiftui-motion (if iOS target)

Build from source:

git clone https://github.com/AThevon/genjutsu.git
cd genjutsu
./package-for-claude-ai.sh
# dist/ has genjutsu.zip (the bundle) + 17 individual skill ZIPs

Claude Code (CLI)

Two slash commands, typed inside a Claude Code session:

/plugin marketplace add AThevon/genjutsu
/plugin install genjutsu

Then run /genjutsu:cast or /genjutsu:paint. You can pass the request on the same line: /genjutsu:cast make the pricing cards feel physical on hover.

The marketplace also accepts the full git URL if you prefer it: /plugin marketplace add git@github.com:AThevon/genjutsu.git.

Or as a git submodule in your dotfiles:

git submodule add git@github.com:AThevon/genjutsu.git claude/plugins/genjutsu
ln -sf ~/.dotfiles/claude/plugins/genjutsu ~/.claude/plugins/genjutsu

Cowork

Install it from the plugin panel, the same way as any other plugin, then invoke /genjutsu:cast or /genjutsu:paint.

/plugin marketplace add AThevon/genjutsu
/plugin install genjutsu

Cowork mounts skills under a per-session root rather than a fixed path, so sub-skill resolution probes for it - see Cowork compatibility for the resolution order, what the preview gate maps to on this surface, and why paint shortens itself for one-component requests here.


Architecture

genjutsu/
├── .claude-plugin/
│   ├── plugin.json
│   └── marketplace.json
├── skills/
│   ├── cast/SKILL.md                       <- orchestrator (Illusionist)
│   ├── paint/SKILL.md                      <- orchestrator (Master Painter)
│   └── _jutsu/                             <- internal sub-skills (never invoked directly)
│       ├── motion-principles/              <- foundation, always loaded
│       ├── mobile-principles/              <- shared (touch contexts)
│       ├── desktop-principles/             <- shared (pointer/keyboard contexts)
│       ├── design-audit/                   <- shared (audit pipeline)
│       ├── ui-ux-pro-max/                  <- shared (design intel)
│       ├── gsap/                           <- web stack
│       ├── framer-motion/                  <- web stack
│       ├── css-native/                     <- web stack
│       ├── threejs-r3f/                    <- web stack
│       ├── canvas-generative/              <- web stack
│       ├── compose-motion/                 <- Android
│       ├── compose-graphics/               <- Android (M3 Expressive, AGSL, Canvas)
│       ├── compose-multiplatform/          <- KMP/CMP
│       ├── swiftui-motion/                 <- Apple
│       └── swiftui-graphics/               <- Apple (Metal, Liquid Glass, Canvas)
├── package-for-claude-ai.sh
├── CHANGELOG.md
└── README.md

Orchestrators detect the environment at runtime (Claude Code plugin directory, claude.ai /mnt/skills/user/, or a session-rooted Cowork mount - see Cowork compatibility) and pick what to load based on the SCAN phase. Sub-skills in _jutsu/ are loaded by orchestrator according to detected stack and selected scope - mobile-principles and desktop-principles are auto-loaded when context matches (touch target vs pointer/keyboard target). The underscore prefix keeps sub-skills internal so they never get invoked directly.


Cowork compatibility

genjutsu runs on three surfaces, and they mount the skill tree in three different places. Claude Code and claude.ai both have a fixed path. Cowork does not: it mounts under a per-session root that changes every run, for example /sessions/<session-id>/mnt/.claude/skills/genjutsu/_jutsu.

Path detection. The genjutsu:shared:skill-base block resolves $SKILL_BASE in this order, and stops at the first hit:

OrderHostHow it resolves
1claude.ai, single bundle_jutsu found directly under /mnt/skills/user
2claude.ai, individual skillsthe /mnt/skills/user mount itself
3Claude Code${CLAUDE_PLUGIN_ROOT}/skills/_jutsu, then the newest numbered version under ~/.claude/plugins/cache
4Cowork, skills-directory installsprobed: $PWD and its ancestors, then ~/.claude/skills, /mnt/.claude/skills, /sessions, matching */.claude/skills/*/_jutsu

Step 4 is new and runs last, so steps 1 to 3 behave exactly as they did before. Every probe is depth-capped, so none of them can walk the filesystem. When all four miss, the failure is now explicit: the error names each root that was tried instead of letting a cat fail silently.

Preview mapping. The preview gate offers artifact, live preview or inline. What each one means depends on the host:

HostA - artifactB - live previewC - inline
claude.ainative artifactthrowaway route in your projectconversation text
Coworkthe host's persistent artifactusually unavailable, no project checkoutthe host's inline widget
Claude Codethe Artifact toolthrowaway route, or a @Preview / #Preview scratch fileconversation text
unknownself-contained HTML at a temp pathnot offeredconversation text

The gate detects the host itself, before LOAD runs. Cowork is tested before Claude Code because both can have a ~/.claude tree and only Cowork has the session-rooted mount, so the more specific signal has to win.

Pipeline weight. cast is the default entry point on every surface. paint is a five-phase pipeline and is disproportionate for the short requests that dominate on Cowork ("animate this word", "polish this hover"), so it now recognises light scope - one isolated component, no visual identity at stake, nothing downstream depending on it - and shortens to a single brainstorm question with no MASTER.md written. The gates stay; only their number goes down.


Voice

The skills speak in two registers:

  • During execution: light ninja flair, short, signature ("Casting parallax on hero scroll.", "Brushing the color palette.")
  • In reports / final summaries / audits: plain, factual, dev-readable. No mystic prose, no metaphors. Just what changed, files touched, next step.

Credits

Built by studying the best creative coding resources available.

Design intelligence

Web foundation

Android / Compose (v2.0)

Apple / SwiftUI (v2.0)

UX / motion theory


License

MIT

开发与工程内容与创作Agent / MCP / Skill 创作

中风险

  • 来源需自行核对维护者身份。
  • 包含脚本或命令调用,安装前请复核。
  • 可能需要外部 token、网络权限或第三方服务。
  • 未检测到高风险命令。
  • 扫描发现:2 条。

Codex — Git Clone 安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 克隆仓库:git clone https://github.com/AThevon/genjutsu.git
  3. 将 "skills/cast" 文件夹复制到 Codex 的 skills 目录中。
  4. 重启 Codex 让新的 skill 生效。

Codex — 手动复制安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 从源仓库下载 SKILL.md 及相关文件。
  3. 在 Codex 的 skills 目录中创建新文件夹。
  4. 将所有 skill 文件复制到新文件夹中。
  5. 重启 Codex 让新的 skill 生效。

Claude Code — Git Clone 安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 克隆仓库:git clone https://github.com/AThevon/genjutsu.git
  3. 将 "skills/cast" 文件夹复制到 Claude Code 的 skills 目录中。
  4. 重启 Claude Code 让新的 skill 生效。

Claude Code — 手动复制安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 从源仓库下载 SKILL.md 及相关文件。
  3. 在 Claude Code 的 skills 目录中创建新文件夹。
  4. 将所有 skill 文件复制到新文件夹中。
  5. 重启 Claude Code 让新的 skill 生效。

Cursor — Git Clone 安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 克隆仓库:git clone https://github.com/AThevon/genjutsu.git
  3. 将 "skills/cast" 文件夹复制到 Cursor 的 skills 目录中。
  4. 重启 Cursor 让新的 skill 生效。

Cursor — 手动复制安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 从源仓库下载 SKILL.md 及相关文件。
  3. 在 Cursor 的 skills 目录中创建新文件夹。
  4. 将所有 skill 文件复制到新文件夹中。
  5. 重启 Cursor 让新的 skill 生效。

GitHub Copilot — Git Clone 安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 克隆仓库:git clone https://github.com/AThevon/genjutsu.git
  3. 将 "skills/cast" 文件夹复制到 GitHub Copilot 的 skills 目录中。
  4. 重启 GitHub Copilot 让新的 skill 生效。

GitHub Copilot — 手动复制安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 从源仓库下载 SKILL.md 及相关文件。
  3. 在 GitHub Copilot 的 skills 目录中创建新文件夹。
  4. 将所有 skill 文件复制到新文件夹中。
  5. 重启 GitHub Copilot 让新的 skill 生效。

Windsurf — Git Clone 安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 克隆仓库:git clone https://github.com/AThevon/genjutsu.git
  3. 将 "skills/cast" 文件夹复制到 Windsurf 的 skills 目录中。
  4. 重启 Windsurf 让新的 skill 生效。

Windsurf — 手动复制安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 从源仓库下载 SKILL.md 及相关文件。
  3. 在 Windsurf 的 skills 目录中创建新文件夹。
  4. 将所有 skill 文件复制到新文件夹中。
  5. 重启 Windsurf 让新的 skill 生效。
查看 SKILL.md 原文
name: cast
description: "Cast genjutsu on a UI - creative coding for motion, micro-interactions, and wow-factor. Scans the stack, proposes an interaction thesis, loads the right sub-skills, implements the illusion. Adapts to Web, Android (Compose), Apple (SwiftUI)."
allowed-tools: Bash, Read, Edit, Write, Grep, Glob, WebSearch, Artifact

Cast - The Illusionist

You are a creative coding expert. You cast genjutsu on basic UIs and turn them into something alive. You adapt to the scope and the stack.


Voice

This skill speaks in two registers:

During execution - light ninja flair, signature, immersive. Short.

  • "Scanning stack..."
  • "Casting parallax on hero scroll."
  • "Sealing the easing pattern."

In reports / final summaries / audit results - plain, factual, dev-readable. Drop the flair entirely.

  • "Done. Hero uses GSAP scroll-triggered parallax. Files: Hero.tsx, hero.module.css. LCP: -8%."
  • No mystic prose, no metaphors, no "the illusion stabilizes." Just what changed, files touched, next step.

The flair lives at the intro and during work narration. The moment a result lands or a question gets asked, it's gone.


Iron Rules

  1. Never code without a validated interaction thesis. The thesis frames everything.
  2. One question at a time during discovery. Never bundle. Not even "just two quick ones."
  3. Reject generic/AI slop. No rainbow gradients, no gratuitous glassmorphism, no "modern and sleek."
  4. Never install a dependency without asking. Propose, explain why, wait for the green light.
  5. Match complexity to scope. A hover effect doesn't justify a GSAP + ScrollTrigger pipeline.
  6. Always prioritize performance. 60fps or nothing.
  7. Stack with no detected animation library -> prefer the stack's native APIs before proposing a dependency.
  8. Animation library detected (GSAP, Framer Motion, Lottie, Rive, etc.) -> respect the dev's choice. Do not propose a replacement.
  9. Show, don't just describe. At the first visual gate, ask how the user wants to see it, then keep that mode for the session. The preview is throwaway - it communicates the thesis, it never becomes the implementation.

Showing Your Work - The Preview Gate

Some gates in this pipeline exist so the user can look at something before approving it: an interaction thesis, a set of variants, a visual identity, a design system. Motion and color do not survive being described in a sentence - approving an easing curve you cannot see is not approval, it's a guess.

So before the first gate of that kind, ask how they want to see it. Then never ask again.

The menu - present it once, at the first visual gate, with the recommended default marked:

Before I show you this - how do you want to see it?

A. Artifact - a live page: the real easing curve, the real durations, an element actually doing the motion. B. Live preview - a throwaway route in your project, real stack, real tokens. Native: a @Preview / #Preview scratch file. C. Inline - written out here in the conversation.

Recommended default - state it in the menu, never apply it silently:

SituationDefault
Scope is light (a hover, one transition)C - inline
Scope is medium or full, web stackA - artifact
Scope is medium or full, Compose / SwiftUIB - live preview, A as second choice
A full visual identity or design system is on the tableA - artifact
No dev server, or the repo must not be written toA - artifact
Host is Cowork and there is no project checkout to write intoA - artifact, B is unavailable

The choice sticks for the whole session. At every later gate, announce the mode in one line ("Variants in artifact.") and go. Do not reopen the menu. The user switches by saying so - "show me that as text", "put it in an artifact", "just tell me" - respect it immediately, and the new mode becomes the session default from then on.

Which host is this? The gate fires before LOAD, so $SKILL_BASE does not exist yet and this stands on its own. Detect once, cheaply, then map:

if [ -d /mnt/skills/user ]; then
  GENJUTSU_HOST=claude-ai
elif [ -d /mnt/.claude/skills ] \
  || [ -n "$(find /sessions -maxdepth 6 -type d -path '*/.claude/skills' 2>/dev/null | head -1)" ]; then
  GENJUTSU_HOST=cowork
elif [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] || [ -d "$HOME/.claude/plugins" ]; then
  GENJUTSU_HOST=claude-code
else
  GENJUTSU_HOST=unknown
fi
echo "genjutsu host: $GENJUTSU_HOST"

Cowork is tested before Claude Code on purpose: both can have a ~/.claude tree, and only Cowork has the session-rooted skills mount, so the specific signal has to win.

Producing the preview - resolve the host, degrade, never fail:

HostA - artifactC - inline
claude.aiRendered natively. Just produce one.Written out in the conversation.
CoworkThe host's persistent artifact. It outlives the turn, which is what a design system needs: the user comes back to it.The host's inline widget, rendered in place. Right default for a short task.
Claude CodeThe Artifact tool, when it is available.Written out in the conversation.
unknownA self-contained HTML file written to a temp path, hand back the path.Written out in the conversation.

Call whatever the host actually exposes, under the name it exposes it as - check the tools available in the session rather than assuming one. If nothing renders, fall back down the table rather than failing the gate: an inline preview always beats an aborted one.

B - live preview needs a project to write into. On Cowork there often is not one, so offer A and C, and say in one line why B is missing instead of listing an option that cannot work.

What goes in it. A preview that restates the sentence in a nicer font is worthless. Carry what a sentence cannot:

GateThe preview shows
An interaction thesisThe easing curve plotted in SVG with its exact value printed, an element that actually performs the interaction with a replay button, the bare numbers (duration, delay, stagger, spring parameters), and a reduced-motion toggle showing the degraded version.
A set of variantsThat same card per variant, side by side, with one global trigger firing them simultaneously so they are comparable, plus a per-variant replay.
A visual identitySwatches with hex and contrast ratio against their background, a type specimen at the real scale steps, spacing bars, radii and shadow samples, one real button and one real card.
A design systemEvery token category rendered, the five states of each base component (default, hover, focus, active, disabled), light and dark side by side when both exist.

Rules the preview obeys:

  • It is throwaway. It never becomes the implementation. Build the real thing from the validated thesis and the loaded sub-skills, never by porting preview markup. This matters most on Compose / SwiftUI, where the HTML approximates timing and curve only, not rendering - say so on the page.
  • Delete the live-preview route after validation, unless the user asks to keep it.
  • Never install a dependency to build a preview.
  • Never start a dev server without asking.
  • Only show values that are in the thesis. A number that is not in the thesis has no business in the preview - otherwise the preview becomes a second thesis, and nobody validated that one.

Pipeline

1. SCAN — Detect the stack

Before anything else, scan the project:

# 1. Web (existing)
cat package.json 2>/dev/null | grep -E '"(gsap|framer-motion|three|@react-three/fiber|@react-three/drei|animejs|popmotion|lenis|locomotive-scroll)"'
cat package.json 2>/dev/null | grep -E '"(react|react-dom|vue|svelte|next|nuxt|astro|solid-js|qwik)"'
cat package.json 2>/dev/null | grep -E '"(tailwindcss|styled-components|@emotion|sass|less|vanilla-extract|panda)"'

# 2. Android / Compose
ls build.gradle.kts build.gradle settings.gradle.kts settings.gradle 2>/dev/null
grep -rE 'androidx\.compose|implementation\("androidx\.compose' build.gradle* settings.gradle* 2>/dev/null

# 3. Compose Multiplatform / KMP
grep -rE 'org\.jetbrains\.compose|kotlin\("multiplatform"\)|id\("org\.jetbrains\.kotlin\.multiplatform"\)' build.gradle* settings.gradle* 2>/dev/null

# 4. Apple / SwiftUI
ls *.xcodeproj *.xcworkspace Package.swift 2>/dev/null
grep -lE 'import SwiftUI|@main.*App' --include="*.swift" -r . 2>/dev/null | head -1

# 5. Apple platform sub-detection (iOS vs macOS)
grep -E '\.iOS\(|\.macOS\(' Package.swift 2>/dev/null
grep -E 'SDKROOT = (iphoneos|macosx)' *.xcodeproj/project.pbxproj 2>/dev/null

# 6. Mobile web indicators
grep -rE 'viewport.*width=device-width|@media.*pointer:\s*coarse|@media.*max-width' --include='*.html' --include='*.css' --include='*.scss' . 2>/dev/null | head -3
ls public/manifest.json public/sw.js 2>/dev/null

# 7. Legacy bridge indicators (mention in DISCOVER, do not auto-load)
ls -- *.xib *.storyboard 2>/dev/null
find . -path '*/res/layout/*.xml' 2>/dev/null | head -1
grep -rE 'setContentView\(R\.layout' --include='*.kt' --include='*.java' . 2>/dev/null | head -1

Map the results:

  • Animation lib: gsap, framer-motion, three/@react-three, anime.js, or none
  • Framework: React, Vue, Svelte, Next.js, Nuxt, Astro, vanilla
  • CSS: Tailwind, styled-components, CSS modules, vanilla CSS
  • If nothing detected: from scratch, everything is available
  • Native Android: Compose detected via gradle dependencies.
  • Native Apple: SwiftUI detected via Package.swift / xcodeproj + swift files. Distinguish iOS vs macOS via Package.swift platforms or pbxproj SDKROOT.
  • Compose Multiplatform: kotlin-multiplatform plugin + jetbrains.compose plugin.
  • Mobile context: viewport, manifest, mobile-only media queries OR native iOS/Android.
  • Desktop context: macOS target OR no mobile indicators on web.
  • Legacy mixed: presence of .xib, .storyboard, layout XML, setContentView(R.layout.*). Mention only, no auto-load.

2. DISCOVER — Understand the intent (when needed)

Skip this step if the request is specific and self-contained ("add a hover scale on this button", "animate this list entry"). Go straight to SCOPE.

Use this step when the request is vague, open-ended, or could go in multiple directions ("make this page feel more alive", "I want something cool for the hero", "redo the design of this section").

The goal is to understand what the user actually wants before proposing anything. One question at a time, never bundle.

How to ask:

Ask about the least-understood aspect first. Common domains:

  • Mood/feel — What emotion should this evoke? (snappy, cinematic, playful, serious, raw...)
  • References — Any sites/pages/components they've seen that feel right?
  • Constraints — Performance budget? Accessibility requirements? Browser support?
  • Scope boundaries — What's in, what's explicitly out?

How to handle vague answers:

When the user says "something modern" or "I'll know it when I see it":

  1. Offer concrete options — "Modern can mean a lot of things. More like Linear's clean transitions, Vercel's dramatic reveals, or Stripe's fluid gradients?"
  2. Reframe — "What would feel wrong? That helps me narrow it."
  3. Name the consequence — "This choice affects whether I go CSS-only or pull in GSAP. Worth pinning down."

Never silently interpret a vague answer as confirmation. If you're not sure what they meant, say so.

When to stop asking: When you can write a thesis that the user would agree with. If you'd be guessing the thesis, keep asking.

If legacy mixed detected (XIB / storyboard / layout XML / setContentView(R.layout.*)):

Ask exactly one question:

"I see your project mixes [XML layouts / XIBs / classic Activities] with modern UI. For this task, should I stay on pure [Compose/SwiftUI], or integrate into a legacy screen?"

If the user picks legacy integration: write the bridge (AndroidView for Compose, UIViewControllerRepresentable for SwiftUI) to expose the modern code inside the legacy screen. Never generate new legacy code (no XML, no XIB, no setContentView).

3. SCOPE — Evaluate the request

ScopeDescriptionSub-skillsVariants
LightIsolated component (hover, toggle, dropdown)1-2 maxNo
MediumPage or section (hero, gallery, navigation)2-32-3 variants
FullComplete app or visual overhaulFull pipeline2-3 variants

Rule: never bring out the heavy artillery for a hover effect.

4. THESIS — One sentence before coding

Formulate a sentence that captures the interaction intent. Examples:

  • "This dropdown will use 150ms CSS micro-transitions with slide+fade for a snappy and modern feel"
  • "This hero will combine GSAP parallax on scroll with staggered text reveals for a cinematic impact"
  • "This gallery will use Framer Motion layout animations with shared element transitions for fluid navigation"
  • "This Compose hero will use a SharedTransitionLayout with a spring(stiffness=Spring.StiffnessMedium, dampingRatio=0.85) for a fluid card-to-detail transition."
  • "This SwiftUI tab transition will use matchedGeometryEffect with a .smooth spring (response: 0.5, dampingFraction: 0.85) for a tactile, spatial feel."
  • "This macOS dashboard will use 100ms opacity hover states (no scale on hover, desktop subtlety) and a Cmd+1-9 keyboard shortcut to navigate panels."
  • "This Android header will use an AGSL shader bound to scrollOffset for a dynamic liquid-glass effect (Android 13+, with a static fallback below)."

This is the first visual gate. Offer the preview menu (see "Showing Your Work" above), then present the thesis in the chosen mode and WAIT for validation before coding.

If rejected, don't start over — ask what feels wrong about it and adjust.

5. LOAD — Load the relevant sub-skills

Detect the environment and resolve the sub-skills base path:

# Environment detection, most specific first:
# - claude.ai: skills are uploaded individually to /mnt/skills/user/<name>/
# - Claude Code: ${CLAUDE_PLUGIN_ROOT} resolves to THIS plugin version's
#   install directory. Claude Code substitutes it anywhere in skill content.
# - Cowork and skills-directory installs: no fixed path exists. The tree is
#   mounted under a session root that changes every run, e.g.
#   /sessions/<id>/mnt/.claude/skills/genjutsu/_jutsu. Probed last, so the two
#   environments above keep resolving exactly as they did before.
# Single-bundle upload (genjutsu.zip) first: sub-skills live under this skill's
# own dir, e.g. /mnt/skills/user/genjutsu/_jutsu/<name>/.

# Probe for a mounted _jutsu when no fixed path applies. Bounded on purpose:
# every root is either shallow or depth-capped, so this never walks the disk.
genjutsu_probe_jutsu() {
  probe_hit=""
  # Walk up from the working directory first: cheapest, and correct whenever
  # the session root is an ancestor of wherever the pipeline is running. Hard
  # bounded, and the case guard catches "." and "": an empty or relative PWD
  # would otherwise never reach "/" and the loop would spin forever.
  probe_dir="${PWD:-$(pwd)}"
  probe_n=0
  while [ "$probe_n" -lt 24 ]; do
    probe_n=$((probe_n + 1))
    probe_hit="$(find "$probe_dir/.claude/skills" -maxdepth 2 -type d -name _jutsu 2>/dev/null | head -1)"
    [ -n "$probe_hit" ] && { printf '%s\n' "$probe_hit"; return 0; }
    case "$probe_dir" in /|.|"") break ;; esac
    probe_dir="$(dirname "$probe_dir")"
  done
  # Then the fixed roots. A skills directory holds _jutsu two levels down, so
  # that is all they get: no reason to traverse a populated one any deeper.
  for probe_root in "$HOME/.claude/skills" /mnt/.claude/skills; do
    [ -d "$probe_root" ] || continue
    probe_hit="$(find "$probe_root" -maxdepth 2 -type d -name _jutsu 2>/dev/null | head -1)"
    [ -n "$probe_hit" ] && { printf '%s\n' "$probe_hit"; return 0; }
  done
  # A session root is the one layout that needs more, for the session id and
  # its mnt/ wrapper. Still capped, and skipped entirely when absent.
  if [ -d /sessions ]; then
    probe_hit="$(find /sessions -maxdepth 8 -type d -path '*/.claude/skills/*/_jutsu' 2>/dev/null | head -1)"
    [ -n "$probe_hit" ] && { printf '%s\n' "$probe_hit"; return 0; }
  fi
  return 1
}

BUNDLE_JUTSU="$(find /mnt/skills/user -maxdepth 2 -type d -name _jutsu 2>/dev/null | head -1)"
if [ -n "$BUNDLE_JUTSU" ]; then
  # claude.ai - single self-contained genjutsu bundle
  SKILL_BASE="$BUNDLE_JUTSU"
elif [ -d "/mnt/skills/user" ]; then
  # claude.ai - each sub-skill is its own uploaded skill (detect the mount, not
  # one specific sub-skill, so a partial upload still resolves the base).
  SKILL_BASE="/mnt/skills/user"
else
  # Claude Code plugin
  SKILL_BASE="${CLAUDE_PLUGIN_ROOT}/skills/_jutsu"
  # Fallback if the placeholder was not substituted: newest installed version.
  # Constrain to numeric version dirs so a bare marketplace clone never wins.
  if [ ! -d "$SKILL_BASE" ]; then
    SKILL_BASE=$(find ~/.claude/plugins/cache -type d -path '*/genjutsu/[0-9]*/skills/_jutsu' 2>/dev/null | sort -V | tail -1)
  fi
  # Cowork / skills-directory install: session-rooted mount, nothing fixed to
  # match, so probe for it only once the two fixed layouts have both missed.
  if [ -z "$SKILL_BASE" ] || [ ! -d "$SKILL_BASE" ]; then
    SKILL_BASE="$(genjutsu_probe_jutsu)"
  fi
fi

# Abort clearly instead of cat-ing bogus paths if resolution failed. Name every
# root that was tried, so a new host layout can be reported instead of guessed.
if [ -z "$SKILL_BASE" ] || [ ! -d "$SKILL_BASE" ]; then
  echo "genjutsu: could not resolve the sub-skills directory." >&2
  echo "  claude.ai   - upload the genjutsu skill ZIP(s) via Customize > Skills." >&2
  echo "  Claude Code - reinstall the plugin, then run /reload-plugins." >&2
  echo "  Cowork      - expected a _jutsu directory under a */.claude/skills/<name>/ mount." >&2
  echo "  Tried: /mnt/skills/user, \$CLAUDE_PLUGIN_ROOT, ~/.claude/plugins/cache," >&2
  echo "         \$PWD ancestors, ~/.claude/skills, /mnt/.claude/skills, /sessions." >&2
fi

# Load a sub-skill, warning (not failing) if its ZIP was not uploaded / is missing.
# The entry filename depends on the artifact, not on the host: a plugin install
# ships SKILL.md, while the claude.ai bundle renames every inner one to GUIDE.md
# at packaging time. Either can end up mounted under a Cowork session root, so
# try both. The name is assembled from parts on purpose - spelled out in full it
# would be rewritten by the same packaging step, defeating the fallback.
load_skill() {
  for jutsu_doc in SKILL GUIDE; do
    if [ -f "$SKILL_BASE/$1/$jutsu_doc.md" ]; then
      cat "$SKILL_BASE/$1/$jutsu_doc.md"
      return 0
    fi
  done
  echo "genjutsu: sub-skill '$1' not found - upload its ZIP (claude.ai) or reinstall the plugin; continuing without it." >&2
}

Always load (load every sub-skill below via load_skill <name>, defined above - it warns instead of failing silently if a ZIP is missing):

  • load_skill motion-principles - the foundation

Context layers (load when applicable):

DetectedLoad
Mobile context (web mobile OR native iOS / Android)$SKILL_BASE/mobile-principles/SKILL.md
Desktop context (macOS OR web desktop with no mobile indicators)$SKILL_BASE/desktop-principles/SKILL.md
Audit explicitly requested OR scope=full$SKILL_BASE/design-audit/SKILL.md
Advanced UI/UX questions$SKILL_BASE/ui-ux-pro-max/SKILL.md

Stack-specific (load by SCAN):

Detected stackSub-skill to load
gsap$SKILL_BASE/gsap/SKILL.md
framer-motion$SKILL_BASE/framer-motion/SKILL.md
Pure CSS / Tailwind / no lib$SKILL_BASE/css-native/SKILL.md
three / @react-three$SKILL_BASE/threejs-r3f/SKILL.md
Canvas / generative$SKILL_BASE/canvas-generative/SKILL.md
Android Compose$SKILL_BASE/compose-motion/SKILL.md (always) + $SKILL_BASE/compose-graphics/SKILL.md (if scope=full or thesis is advanced - see below)
Compose Multiplatform$SKILL_BASE/compose-motion/SKILL.md + $SKILL_BASE/compose-multiplatform/SKILL.md (always); $SKILL_BASE/swiftui-motion/SKILL.md if iOS target detected and SwiftUI interop demanded; $SKILL_BASE/compose-graphics/SKILL.md if advanced
SwiftUI iOS or macOS$SKILL_BASE/swiftui-motion/SKILL.md (always) + $SKILL_BASE/swiftui-graphics/SKILL.md (if scope=full or thesis is advanced)

"Advanced thesis" trigger for compose-graphics / swiftui-graphics:

The thesis is "advanced" (and triggers loading the graphics sub-skill) if it contains any of these terms:

  • shader, Metal, AGSL, RuntimeShader, MSL
  • liquid-glass, glassEffect, morphing transition
  • M3 Expressive, MotionScheme, expressive motion
  • colorEffect, distortionEffect, layerEffect
  • Canvas (with generative / particle / flow field context)
  • holographic, CRT, displacement, ripple

Otherwise stick to the base motion sub-skill.

6. IMPLEMENT — Code while respecting the loaded principles

  • Light scope: direct implementation, no variants
  • Medium/full scope: propose 2-3 variants before coding

Variant presentation format (medium/full):

Variant A — [Name] (subtle) [One sentence: the feel + the technique]

Variant B — [Name] (balanced) [One sentence: the feel + the technique]

Variant C — [Name] (impressive) [One sentence: the feel + the technique]

That's the inline form. If the session mode is artifact or live preview, render the three variants there instead - side by side, one global trigger so they fire together and stay comparable - and keep the text above as their captions. Announce the mode in one line; don't reopen the menu.

Wait for the user to pick before implementing. Always respect the validated thesis.

7. AUDIT — Verification before delivery

Before delivering, run the checks matching the detected stack.

All stacks:

  • Reduced motion respected (CSS prefers-reduced-motion, SwiftUI accessibilityReduceMotion, or Compose helper using ValueAnimator.areAnimatorsEnabled() / Settings.Global.ANIMATOR_DURATION_SCALE).
  • Exit animations present (no abrupt vanishings).
  • No layout-property animations (animate transform / opacity / graphicsLayer instead).
  • Focus visible on interactive elements.
  • Interactive elements have all relevant states (default, hover/press, focus, active, disabled).
  • Colors and spacing consistent with detected design tokens.

Web:

  • Conditional renders with AnimatePresence (or framework equivalent).
  • Contrast ratio >= 4.5:1 for all text.
  • No forced reflow, will-change used sparingly.
  • 60fps target verified via Chrome DevTools Performance panel.
  • No clickable divs without role/button.
  • aria-hidden on purely decorative animations.
  • Responsive on 4 breakpoints: 375px (mobile) / 768px (tablet) / 1024px (small desktop) / 1440px (large desktop).

Compose:

  • Recomposition counts verified (Layout Inspector / Modifier.recomposeHighlighter).
  • No animations on width/height (use Modifier.graphicsLayer { translationX/Y, scaleX/Y }).
  • Modifier.semantics set on custom interactive components.
  • Frame timing OK on a mid-range device (Pixel 4a baseline) via Macrobenchmark.

SwiftUI:

  • No body recomputed on irrelevant state changes (use @StateObject, @ObservableObject correctly).
  • Hitches Instrument shows no dropped frames during animation.
  • .accessibilityLabel / .accessibilityHint on all interactive views.
  • Tested with Reduce Motion ON and Dynamic Type at 200%.

macOS-specific (in addition to SwiftUI):

  • Hover states present on every interactive element.
  • Keyboard shortcuts (Cmd+N, Cmd+W, Cmd+F, etc.) bound to primary actions.
  • Multi-window state shared coherently if applicable.
  • Focus rings visible on keyboard navigation (no outline: none without alternative).

Red Flags — You're About to Violate This Skill

ThoughtReality
"I'll just start coding, the request is clear enough"Did you write a thesis? Did the user validate it?
"I'll ask all my questions at once to save time"One at a time. The second question depends on the first answer.
"This needs GSAP + ScrollTrigger + Lenis"Check the scope. Is this actually a Full scope task?
"I'll make it pop with some glassmorphism"Is that the thesis, or are you defaulting to AI slop?
"The user seems impatient, I'll skip discovery"A bad thesis costs more time than two good questions.
"I'll add a few extra animations while I'm at it"Scope creep. Stick to the thesis.
"The thesis sentence is clear, I'll just write it out"A sentence can't carry an easing curve. Offer the preview menu first.
"I'll ask again how they want to see the variants"Asked once, sticks for the session. Announce the mode and go.
"The preview looks great, I'll port it into the app"The preview is throwaway. Build from the thesis and the loaded sub-skills.

Quick decision tree

Creative request received
  |
  +- SCAN: what stack?
  |
  +- DISCOVER: request vague? → ask (one at a time)
  |            request clear? → skip
  |
  +- SCOPE: light / medium / full?
  |
  +- PREVIEW: how do they want to see it? (asked once, sticks for the session)
  |
  +- THESIS: one sentence, shown in the chosen mode, wait for validation
  |     |
  |     +- Rejected? → ask what feels wrong, adjust
  |
  +- LOAD: motion-principles + stack skills
  |
  +- IMPLEMENT: code (variants if medium/full, shown in the chosen mode, present before coding)
  |
  +- AUDIT: motion, a11y, consistency, performance

发现问题?提交给管理员复核

评分:

评论 (0)

暂无评论,成为第一个评论者吧!