react-game-ui

安装量: 59
排名: #12593

安装

npx skills add https://github.com/ccalebcarter/purria-skills --skill react-game-ui

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 (

bg-gradient-to-br ${colorMap[color]} )}> {icon}
{label} {value.toLocaleString()} {maxValue && /{maxValue}}
); }

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 {display}; }

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 (

{label} {showValue && ( {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 }} />
); }

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 ( {/ Front /}

{rank} {suitSymbol(suit)}

    {/* 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) { return ( ); }

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 ( +{amount} 🪙 ); }

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

export function ShakeOnError({ error, children }) { return ( {children} ); }

Layout Patterns Game HUD Layout export function GameLayout({ children }: { children: React.ReactNode }) { return (

{/ Top Bar /}
} value={resources.tulipBulbs} label="Tulips" color="green" />

  {/* 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 (

{children}
); }

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 (

{title} {children} ); }

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

export function GameTooltip({ children, content }) { return ( {children} {content} ); }

Accessibility for Games Skip Animation Preference import { useReducedMotion } from 'framer-motion';

export function AnimatedElement({ children }) { const shouldReduceMotion = useReducedMotion();

return ( {children} ); }

Screen Reader Announcements import { useEffect, useRef } from 'react';

export function useAnnounce() { const ref = useRef(null);

const announce = (message: string) => { if (ref.current) { ref.current.textContent = message; } };

return { announce, AnnouncerRegion: () => (

)}; }

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

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

返回排行榜