/** * @file Particle Size Node - Provides particle size control output */ import * as React from "react"; import type { NodeDefinition, NodeRendererProps, InspectorRenderProps, ExternalDataReference, } from "../../../../../types/NodeDefinition"; import classes from "./ParticleSizeNode.module.css"; export type ParticleSizeData = { id: string; value: number; min: number; max: number; step: number; }; export const ParticleSizeRenderer = ({ node, isSelected, isDragging, externalData, onUpdateNode }: NodeRendererProps) => { const sizeData = externalData as ParticleSizeData | undefined; const [value, setValue] = React.useState(sizeData?.value ?? 4); const lastExternalValueRef = React.useRef(undefined); React.useEffect(() => { if (sizeData?.value !== undefined) { setValue(sizeData.value); lastExternalValueRef.current = sizeData.value; } }, [sizeData?.value]); React.useEffect(() => { if (sizeData?.value === undefined) { lastExternalValueRef.current = undefined; return; } if (lastExternalValueRef.current === sizeData.value) { return; } lastExternalValueRef.current = sizeData.value; onUpdateNode({ data: { ...node.data, value: sizeData.value, "size-output": sizeData.value, }, }); }, [node.data, onUpdateNode, sizeData?.value]); const handleChange = (newValue: number) => { setValue(newValue); onUpdateNode({ data: { ...node.data, value: newValue, "size-output": newValue, updatedAt: Date.now(), }, }); }; const sliderMin = sizeData?.min ?? 1; const sliderMax = sizeData?.max ?? 20; const sliderStep = sizeData?.step ?? 1; return (
🌀 Particle Size
{value}px
handleChange(Number(event.target.value))} />
{sliderMin}px - {sliderMax}px
); }; export const ParticleSizeInspectorRenderer = ({ externalData, onUpdateExternalData }: InspectorRenderProps) => { const sizeData = externalData as ParticleSizeData | undefined; const [editedData, setEditedData] = React.useState({ id: sizeData?.id ?? "", value: sizeData?.value ?? 4, min: sizeData?.min ?? 1, max: sizeData?.max ?? 20, step: sizeData?.step ?? 1, }); const handleSave = async () => { if (onUpdateExternalData) { await onUpdateExternalData(editedData); } }; return (

Particle Size

setEditedData({ ...editedData, value: Number(event.target.value) })} />
setEditedData({ ...editedData, min: Number(event.target.value) })} />
setEditedData({ ...editedData, max: Number(event.target.value) })} />
setEditedData({ ...editedData, step: Number(event.target.value) })} />
); }; export const ParticleSizeNodeDefinition: NodeDefinition = { type: "particle-size", displayName: "Particle Size", description: "Adjusts particle size output for connected systems", category: "Effects", defaultData: { title: "Particle Size", }, defaultSize: { width: 220, height: 140 }, ports: [ { id: "size-output", type: "output", label: "Size", position: "right", }, ], renderNode: ParticleSizeRenderer, renderInspector: ParticleSizeInspectorRenderer, loadExternalData: async (ref: ExternalDataReference) => { await new Promise((resolve) => setTimeout(resolve, 200)); return { id: ref.id, value: 6, min: 1, max: 20, step: 1, } satisfies ParticleSizeData; }, updateExternalData: async (_ref: ExternalDataReference, data: unknown) => { await new Promise((resolve) => setTimeout(resolve, 200)); console.log("Updated particle size data:", data); }, };