Token导航 LogoToken导航TokenDH.com
研究检索权限需确认github未标认证来源可访问clear审计未展示

react-game-uiReact game UI 搜索

Agent Skill

用于辅助前端页面、组件、样式和交互逻辑的开发与维护。它适合让 Agent 生成或审查 React、Next.js、Vue、Tailwind、CSS 等相关代码,整理组件结构,或定位布局和性能问题。使用时需要结合项目现有设计系统、路由和构建方式,避免只生成孤立片段;涉及页面改动时,应配合本地预览和构建检查确认视觉效果。

总安装

3,320

周安装

133

GitHub Stars

公开资料未说明

下载量

1,075
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

MIT

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:react-game-ui(React game UI 搜索)
来源仓库:https://github.com/ccalebcarter/purria-skills
仓库路径:skills/react-game-ui
安装命令:
npx skills add ccalebcarter/purria-skills --skill "react-game-ui"
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

AgentSkills.tonpx skills
npx skills add ccalebcarter/purria-skills --skill "react-game-ui"

简介

react-game-ui 用于辅助 React 前端开发与维护。

  • 它适合生成或审查组件代码,定位布局和性能问题。
  • 使用时需结合项目设计系统和路由结构,避免孤立片段。
  • 涉及页面改动时应配合本地预览确认视觉效果。
  • 适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

SKILL.md

name
react-game-ui
description
React game UI patterns using shadcn/ui, Tailwind, and Framer Motion for polished game interfaces. Use when building HUDs, resource bars, scoreboards, modals, tooltips, card components, or any game UI. Includes micro-interactions, animations, responsive layouts, and accessibility for games. Triggers on requests for game interface components, UI animations, or shadcn/ui game patterns.

React Game UI

Production-ready UI patterns for game interfaces using shadcn/ui, Tailwind, and Framer Motion.

Core Components

Resource Bar

import { cn } from '@/lib/utils';
import { motion, AnimatePresence } from 'framer-motion';

interface ResourceBarProps {
  icon: React.ReactNode;
  value: number;
  maxValue?: number;
  label: string;
  color?: 'gold' | 'green' | 'blue' | 'red';
}

const colorMap = {
  gold: 'from-amber-400 to-yellow-500',
  green: 'from-emerald-400 to-green-500',
  blue: 'from-sky-400 to-blue-500',
  red: 'from-rose-400 to-red-500',
};

export function ResourceBar({ 
  icon, 
  value, 
  maxValue, 
  label, 
  color = 'gold' 
}: ResourceBarProps) {
  return (
    <div className="flex items-center gap-2 bg-black/40 backdrop-blur-sm rounded-lg px-3 py-2">
      <div className={cn(
        'w-8 h-8 rounded-full flex items-center justify-center',
        `bg-gradient-to-br ${colorMap[color]}`
      )}>
        {icon}
      </div>
      <div className="flex flex-col">
        <span className="text-xs text-white/60 uppercase tracking-wide">{label}</span>
        <motion.span 
          key={value}
          initial={{ scale: 1.2, color: '#ffd700' }}
          animate={{ scale: 1, color: '#ffffff' }}
          className="text-lg font-bold text-white tabular-nums"
        >
          {value.toLocaleString()}
          {maxValue && <span className="text-white/40">/{maxValue}</span>}
        </motion.span>
      </div>
    </div>
  );
}

Animated Counter

import { useEffect, useRef } from 'react';
import { motion, useSpring, useTransform } from 'framer-motion';

interface AnimatedCounterProps {
  value: number;
  duration?: number;
  className?: string;
}

export function AnimatedCounter({ value, duration = 0.5, className }: AnimatedCounterProps) {
  const spring = useSpring(0, { duration: duration * 1000 });
  const display = useTransform(spring, (v) => Math.floor(v).toLocaleString());
  
  useEffect(() => {
    spring.set(value);
  }, [spring, value]);
  
  return <motion.span className={className}>{display}</motion.span>;
}

Meter/Progress Component

interface MeterProps {
  value: number;         // 0-100
  label: string;
  tier?: 'mini' | 'major' | 'grand';
  showValue?: boolean;
}

const tierStyles = {
  mini: 'h-2',
  major: 'h-3',
  grand: 'h-4',
};

export function Meter({ value, label, tier = 'mini', showValue = true }: MeterProps) {
  const clampedValue = Math.max(0, Math.min(100, value));
  
  return (
    <div className="space-y-1">
      <div className="flex justify-between text-sm">
        <span className="text-white/80">{label}</span>
        {showValue && (
          <span className="text-white/60 tabular-nums">{clampedValue}%</span>
        )}
      </div>
      <div className={cn(
        'w-full bg-white/10 rounded-full overflow-hidden',
        tierStyles[tier]
      )}>
        <motion.div
          className={cn(
            'h-full rounded-full',
            clampedValue >= 50 
              ? 'bg-gradient-to-r from-emerald-500 to-green-400' 
              : 'bg-gradient-to-r from-amber-500 to-orange-400'
          )}
          initial={{ width: 0 }}
          animate={{ width: `${clampedValue}%` }}
          transition={{ type: 'spring', stiffness: 100, damping: 15 }}
        />
      </div>
    </div>
  );
}

Game Card Component

import { motion } from 'framer-motion';

interface GameCardProps {
  suit: 'hearts' | 'diamonds' | 'clubs' | 'spades';
  rank: string;
  faceDown?: boolean;
  onClick?: () => void;
}

export function GameCard({ suit, rank, faceDown = false, onClick }: GameCardProps) {
  const isRed = suit === 'hearts' || suit === 'diamonds';
  
  return (
    <motion.div
      className="relative w-[90px] h-[126px] cursor-pointer perspective-1000"
      onClick={onClick}
      whileHover={{ y: -8, transition: { duration: 0.2 } }}
      whileTap={{ scale: 0.95 }}
    >
      <motion.div
        className="w-full h-full relative"
        style={{ transformStyle: 'preserve-3d' }}
        animate={{ rotateY: faceDown ? 180 : 0 }}
        transition={{ duration: 0.6, type: 'spring' }}
      >
        {/* Front */}
        <div 
          className={cn(
            'absolute inset-0 rounded-lg shadow-lg backface-hidden',
            'bg-white border-2 border-gray-200',
            'flex flex-col items-center justify-center'
          )}
        >
          <span className={cn(
            'text-2xl font-bold',
            isRed ? 'text-red-600' : 'text-gray-900'
          )}>
            {rank}
          </span>
          <span className="text-3xl">{suitSymbol(suit)}</span>
        </div>
        
        {/* Back */}
        <div 
          className="absolute inset-0 rounded-lg shadow-lg backface-hidden bg-gradient-to-br from-indigo-600 to-purple-700"
          style={{ transform: 'rotateY(180deg)' }}
        >
          <div className="w-full h-full rounded-lg border-4 border-white/20 flex items-center justify-center">
            <div className="w-12 h-12 rounded-full bg-white/10" />
          </div>
        </div>
      </motion.div>
    </motion.div>
  );
}

function suitSymbol(suit: string) {
  const symbols = { hearts: '♥', diamonds: '♦', clubs: '♣', spades: '♠' };
  return symbols[suit] || '';
}

Micro-Interactions

Button with Feedback

import { Button } from '@/components/ui/button';
import { motion } from 'framer-motion';

export function GameButton({ 
  children, 
  onClick, 
  variant = 'default',
  ...props 
}: React.ComponentProps<typeof Button>) {
  return (
    <Button
      asChild
      variant={variant}
      onClick={onClick}
      {...props}
    >
      <motion.button
        whileHover={{ scale: 1.02 }}
        whileTap={{ scale: 0.98 }}
        transition={{ type: 'spring', stiffness: 400, damping: 17 }}
      >
        {children}
      </motion.button>
    </Button>
  );
}

Coin Pop Animation

import { motion, AnimatePresence } from 'framer-motion';

interface CoinPopProps {
  amount: number;
  position: { x: number; y: number };
  onComplete: () => void;
}

export function CoinPop({ amount, position, onComplete }: CoinPopProps) {
  return (
    <motion.div
      className="fixed pointer-events-none z-50 text-2xl font-bold text-yellow-400"
      style={{ left: position.x, top: position.y }}
      initial={{ opacity: 1, y: 0, scale: 0.5 }}
      animate={{ opacity: 0, y: -60, scale: 1.2 }}
      exit={{ opacity: 0 }}
      transition={{ duration: 1, ease: 'easeOut' }}
      onAnimationComplete={onComplete}
    >
      +{amount} 🪙
    </motion.div>
  );
}

Shake on Error

const shakeAnimation = {
  x: [0, -10, 10, -10, 10, 0],
  transition: { duration: 0.4 }
};

export function ShakeOnError({ error, children }) {
  return (
    <motion.div animate={error ? shakeAnimation : {}}>
      {children}
    </motion.div>
  );
}

Layout Patterns

Game HUD Layout

export function GameLayout({ children }: { children: React.ReactNode }) {
  return (
    <div className="relative w-full h-screen overflow-hidden bg-gradient-to-br from-stone-900 via-stone-950 to-black">
      {/* Top Bar */}
      <header className="absolute top-0 left-0 right-0 z-20 p-4 flex justify-between items-start">
        <ResourceBar icon={<Flower />} value={resources.tulipBulbs} label="Tulips" color="green" />
        <Scoreboard day={time.day} score={score} />
      </header>
      
      {/* Main Content */}
      <main className="absolute inset-0 flex items-center justify-center pt-20 pb-20">
        {children}
      </main>
      
      {/* Bottom Bar */}
      <footer className="absolute bottom-0 left-0 right-0 z-20 p-4 flex justify-center">
        <PhaseControls />
      </footer>
      
      {/* Side Panel */}
      <aside className="absolute top-20 right-0 bottom-20 z-10 w-80 p-4">
        <MetaPotPanel />
      </aside>
    </div>
  );
}

Responsive Game Board

export function GameBoard({ children }: { children: React.ReactNode }) {
  return (
    <div className="w-full h-full flex items-center justify-center p-4">
      <div className={cn(
        'relative',
        'w-full max-w-[min(90vw,90vh)]',
        'aspect-square'
      )}>
        {children}
      </div>
    </div>
  );
}

Modal & Dialog Patterns

Game Modal with shadcn

import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog';
import { motion, AnimatePresence } from 'framer-motion';

export function GameModal({ open, onOpenChange, title, children }) {
  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="bg-gradient-to-br from-stone-800 to-stone-900 border-amber-500/30">
        <DialogHeader>
          <DialogTitle className="text-amber-400 text-xl">{title}</DialogTitle>
        </DialogHeader>
        <motion.div
          initial={{ opacity: 0, y: 20 }}
          animate={{ opacity: 1, y: 0 }}
          exit={{ opacity: 0, y: 20 }}
        >
          {children}
        </motion.div>
      </DialogContent>
    </Dialog>
  );
}

Tooltip for Game Elements

import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from '@/components/ui/tooltip';

export function GameTooltip({ children, content }) {
  return (
    <TooltipProvider delayDuration={300}>
      <Tooltip>
        <TooltipTrigger asChild>{children}</TooltipTrigger>
        <TooltipContent 
          className="bg-stone-900 border-amber-500/30 text-white"
          sideOffset={8}
        >
          {content}
        </TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
}

Accessibility for Games

Skip Animation Preference

import { useReducedMotion } from 'framer-motion';

export function AnimatedElement({ children }) {
  const shouldReduceMotion = useReducedMotion();
  
  return (
    <motion.div
      animate={{ opacity: 1, y: 0 }}
      transition={shouldReduceMotion ? { duration: 0 } : { duration: 0.3 }}
    >
      {children}
    </motion.div>
  );
}

Screen Reader Announcements

import { useEffect, useRef } from 'react';

export function useAnnounce() {
  const ref = useRef<HTMLDivElement>(null);
  
  const announce = (message: string) => {
    if (ref.current) {
      ref.current.textContent = message;
    }
  };
  
  return { announce, AnnouncerRegion: () => (
    <div
      ref={ref}
      role="status"
      aria-live="polite"
      aria-atomic="true"
      className="sr-only"
    />
  )};
}

// Usage
const { announce, AnnouncerRegion } = useAnnounce();
announce('You won 500 coins!');

Performance Tips

  1. Memoize heavy components: React.memo() for hex cells, cards
  2. Use CSS transforms: GPU-accelerated vs layout-triggering properties
  3. Virtualize large lists: Only render visible items
  4. Debounce rapid updates: Score counters, resource bars
  5. Lazy load modals: Don't mount until needed

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

04

需要参考平台分布和安装热度时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

补充不同宿主或平台的使用分布数据

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Claude Code

25.95%
按下载量换算279

Antigravity

24.36%
按下载量换算262

OpenCode

19.07%
按下载量换算205

Gemini CLI

12.12%
按下载量换算130

Codex

6.87%
按下载量换算74

Cursor

2.92%
按下载量换算31

安全审计

暂无安全审计结果可展示。

权限和风险

权限需确认

当前来源未能明确判断权限范围,默认进入异常复核队列。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills