Created the first version of the character creation feature, including the base layout and starting UI elements for customizing a character.
67 lines
1.3 KiB
TypeScript
67 lines
1.3 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useRef } from "react";
|
|
|
|
import {
|
|
drawTintedSprite,
|
|
getCachedImage,
|
|
hslToRgb,
|
|
type HSL,
|
|
} from "@/lib/character/color-utils";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
type TintedSpriteIconProps = {
|
|
src: string;
|
|
color: HSL;
|
|
size?: number;
|
|
className?: string;
|
|
};
|
|
|
|
export function TintedSpriteIcon({
|
|
src,
|
|
color,
|
|
size = 40,
|
|
className,
|
|
}: TintedSpriteIconProps) {
|
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
|
|
async function render() {
|
|
const canvas = canvasRef.current;
|
|
if (!canvas) return;
|
|
|
|
const ctx = canvas.getContext("2d", { willReadFrequently: true });
|
|
if (!ctx) return;
|
|
|
|
const image = await getCachedImage(src);
|
|
if (cancelled) return;
|
|
|
|
canvas.width = image.width;
|
|
canvas.height = image.height;
|
|
ctx.clearRect(0, 0, image.width, image.height);
|
|
drawTintedSprite(ctx, image, hslToRgb(color.h, color.s, color.l));
|
|
}
|
|
|
|
render();
|
|
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, [src, color]);
|
|
|
|
return (
|
|
<canvas
|
|
ref={canvasRef}
|
|
aria-hidden
|
|
className={cn("block max-h-full max-w-full", className)}
|
|
style={{
|
|
imageRendering: "pixelated",
|
|
width: size,
|
|
height: size,
|
|
}}
|
|
/>
|
|
);
|
|
}
|