import Wheel from "@uiw/react-color-wheel"; import { hsvaToRgba, rgbaToHsva } from "@uiw/color-convert"; import { Copy, RotateCcw } from "lucide-react"; import { useThrottledParameterValue } from "../hooks/useThrottledParameterValue"; import { ParameterValueDisplay } from "./ParameterValueDisplay"; function valuesMatch(left, right) { return JSON.stringify(left) === JSON.stringify(right); } function ParameterHeader({ layer, parameter, onReset, resetDisabled }) { const layerKey = layer.shaderId || layer.shaderName || layer.id; const oscRoute = `/VideoShaderToys/${layerKey}/${parameter.id}`; function copyRoute() { if (navigator.clipboard) { navigator.clipboard.writeText(oscRoute); } } return (
); } function clamp01(value) { return Math.max(0, Math.min(1, Number(value) || 0)); } function colorComponentToHex(value) { return Math.round(clamp01(value) * 255) .toString(16) .padStart(2, "0"); } function colorValueToHex(value) { const values = [...(value ?? [])]; while (values.length < 3) { values.push(0); } return `#${colorComponentToHex(values[0])}${colorComponentToHex(values[1])}${colorComponentToHex(values[2])}`; } function colorValueToHsva(value) { const values = [...(value ?? [])]; while (values.length < 4) { values.push(values.length === 3 ? 1 : 0); } return rgbaToHsva({ r: Math.round(clamp01(values[0]) * 255), g: Math.round(clamp01(values[1]) * 255), b: Math.round(clamp01(values[2]) * 255), a: clamp01(values[3]), }); } function hsvaToColorValue(hsva, alpha) { const rgba = hsvaToRgba({ ...hsva, a: clamp01(alpha ?? hsva.a ?? 1) }); return [ clamp01(rgba.r / 255), clamp01(rgba.g / 255), clamp01(rgba.b / 255), clamp01(alpha ?? rgba.a ?? 1), ]; } export function ParameterField({ layer, parameter, onParameterChange }) { const { appliedValue, beginInteraction, draftValue, endInteraction, isPending, scheduleSendValue, sendValue, } = useThrottledParameterValue(parameter, onParameterChange); const defaultValue = parameter.defaultValue; const resetDisabled = defaultValue === undefined || valuesMatch(draftValue, defaultValue); const resetParameter = () => { if (defaultValue !== undefined) { sendValue(defaultValue); } }; const header = ( ); if (parameter.type === "float") { return (
{header}
scheduleSendValue(Number(event.target.value))} onMouseUp={endInteraction} onTouchEnd={endInteraction} onPointerUp={endInteraction} onKeyDown={beginInteraction} onKeyUp={endInteraction} onBlur={endInteraction} /> sendValue(Number(event.target.value))} onBlur={endInteraction} />
); } if (parameter.type === "vec2") { const values = [...(draftValue ?? [])]; while (values.length < 2) { values.push(0); } return (
{header}
{Array.from({ length: 2 }, (_, index) => ( { const next = [...values]; next[index] = Number(event.target.value); sendValue(next); }} onBlur={endInteraction} /> ))}
); } if (parameter.type === "color") { const values = [...(draftValue ?? [])]; while (values.length < 4) { values.push(values.length === 3 ? 1 : 0); } return (
{header}
scheduleSendValue(hsvaToColorValue(color.hsva, values[3]))} />
); } if (parameter.type === "bool") { return (
{header}
); } if (parameter.type === "enum") { return (
{header}
); } if (parameter.type === "text") { return (
{header} sendValue(event.target.value)} onBlur={endInteraction} />
); } return null; }