8-bit Duel Block
8bitcn/duel-blockFreeBlock
Interactive arena duel with two fighters, HP bars, and hit mechanics.
Install it
npx shadcn@latest add https://www.8bitcn.com/r/duel-block.jsonSource
1"use client";23import Image from "next/image";4import { useCallback, useState } from "react";56import { cn } from "@/lib/utils";78import { Alert, AlertDescription, AlertTitle } from "@/components/ui/8bit/alert";9import { Badge } from "@/components/ui/8bit/badge";10import { Button } from "@/components/ui/8bit/button";11import HealthBar from "@/components/ui/8bit/health-bar";1213import "@/components/ui/8bit/styles/retro.css";1415interface Fighter {16 className?: string;17 hp: number;18 image: string;19 maxHp: number;20 name: string;21 subtitle: string;22}2324interface DuelBlockProps {25 className?: string;26 leftFighter?: Fighter;27 rightFighter?: Fighter;28}2930const hitMessages = [31 "Critical strike!",32 "Holy damage!",33 "Shield block!",34 "Orc smash!",35 "Combo x2!",36 "Parried!",37 "Devastating blow!",38 "Glancing hit!",39];4041export default function DuelBlock({42 leftFighter = {43 name: "Paladin",44 subtitle: "Holy Vanguard",45 image: "/images/8bit-paladin.png",46 hp: 100,47 maxHp: 100,48 },49 rightFighter = {50 name: "Orc Warrior",51 subtitle: "Arena Berserker",52 image: "/images/8bit-orc-warrior.png",53 hp: 100,54 maxHp: 100,55 },56 className,57}: DuelBlockProps) {58 const [left, setLeft] = useState(leftFighter);59 const [right, setRight] = useState(rightFighter);60 const [round, setRound] = useState(1);61 const [lastMessage, setLastMessage] = useState("Fight!");62 const [lastHit, setLastHit] = useState<"left" | "right" | null>(null);6364 const winner =65 left.hp <= 0 ? right.name : right.hp <= 0 ? left.name : null;6667 const handleHit = useCallback(() => {68 if (winner) {69 return;70 }7172 const damage = Math.floor(Math.random() * 20) + 5;73 const msg = hitMessages[Math.floor(Math.random() * hitMessages.length)];7475 if (round % 2 === 1) {76 // Paladin attacks orc77 setRight((f) => ({ ...f, hp: Math.max(0, f.hp - damage) }));78 setLastMessage(`${left.name}: ${msg} -${damage} HP`);79 setLastHit("right");80 } else {81 // Orc attacks paladin82 setLeft((f) => ({ ...f, hp: Math.max(0, f.hp - damage) }));83 setLastMessage(`${right.name}: ${msg} -${damage} HP`);84 setLastHit("left");85 }8687 setRound((r) => r + 1);88 }, [round, winner, left.name, right.name]);8990 const handleReset = useCallback(() => {91 setLeft(leftFighter);92 setRight(rightFighter);93 setRound(1);94 setLastMessage("Round 1 — Fight!");95 setLastHit(null);96 }, [leftFighter, rightFighter]);9798 return (99 <div100// … truncated
What it pulls in
Other registry items
Files it writes
More from 8bitcn
All 121 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| 8-bit Advanced 1advanced1 | 8bitcn | Blocks | Free | no deps · 3 files | |
| 8-bit Advanced 2advanced2 | 8bitcn | Blocks | Free | no deps · 5 files | |
| 8-bit Advanced 3advanced3 | 8bitcn | Blocks | Free | no deps · 6 files | |
| 8-bit Audio Settingsaudio-settings | 8bitcn | Blocks | Free | 2 deps · 7 files | |
| 8-bit Chapter Introchapter-intro | 8bitcn | Blocks | Free | no deps · 3 files | |
| 8-bit Character Sheetcharacter-sheet | 8bitcn | Blocks | Free | no deps · 9 files | |
| 8-bit Chartchart | 8bitcn | Blocks | Free | no deps · 3 files | |
| 8-bit Chart Area Stepchart-area-step | 8bitcn | Blocks | Free | no deps · 3 files |
