"use client"; import { useState, useCallback } from "react"; interface FlowSplits { printer: number; creator: number; community: number; } const DEFAULT_SALE_PRICE = 29.99; const DEFAULT_PRODUCTION_COST = 9.25; // Min production cost as fraction of price (Printful cost floor) const MIN_PRINTER_FRACTION = 0.15; export function RevenueFlowSankey() { const [salePrice] = useState(DEFAULT_SALE_PRICE); const [splits, setSplits] = useState(() => { const printer = DEFAULT_PRODUCTION_COST / DEFAULT_SALE_PRICE; const remaining = 1 - printer; return { printer, creator: remaining * 0.35, community: remaining * 0.65, }; }); const handleSplitChange = useCallback( (key: keyof FlowSplits, newValue: number) => { setSplits((prev) => { const updated = { ...prev, [key]: newValue }; // Enforce minimum printer cost if (updated.printer < MIN_PRINTER_FRACTION) { updated.printer = MIN_PRINTER_FRACTION; } // Normalize so all splits sum to 1 const total = updated.printer + updated.creator + updated.community; if (total === 0) return prev; return { printer: updated.printer / total, creator: updated.creator / total, community: updated.community / total, }; }); }, [] ); const printerAmount = salePrice * splits.printer; const creatorAmount = salePrice * splits.creator; const communityAmount = salePrice * splits.community; return (
{/* SVG Sankey Diagram */}
{/* Glow filters */} {/* ── Source node: Sale ── */} Sale ${salePrice.toFixed(2)} {/* ── Flow paths (Bezier curves) ── */} {/* ── Target nodes ── */} {/* Printer */} P Printer ${printerAmount.toFixed(2)} ({(splits.printer * 100).toFixed(0)}%) {/* Creator */} C Creator ${creatorAmount.toFixed(2)} ({(splits.creator * 100).toFixed(0)}%) {/* Community */} $ Community ${communityAmount.toFixed(2)} ({(splits.community * 100).toFixed(0)}%)
{/* ── Interactive Sliders ── */}
handleSplitChange("printer", v)} /> handleSplitChange("creator", v)} /> handleSplitChange("community", v)} />

Drag the sliders to see how revenue flows between production, creator, and community. The community sets its own margin — every dollar above production cost funds collective work.

); } /* ── Bezier flow path ── */ function SankeyFlow({ startX, startY, endX, endY, width, gradient, }: { startX: number; startY: number; endX: number; endY: number; width: number; gradient: string; }) { const midX = (startX + endX) / 2; const d = `M ${startX} ${startY} C ${midX} ${startY}, ${midX} ${endY}, ${endX} ${endY}`; return ( ); } /* ── Slider for a single flow channel ── */ function FlowSlider({ label, sublabel, value, amount, color, onChange, }: { label: string; sublabel: string; value: number; amount: number; color: string; onChange: (v: number) => void; }) { return (
{label} {sublabel}
${amount.toFixed(2)}
onChange(Number(e.target.value) / 100)} className="w-full h-2 rounded-full appearance-none cursor-pointer" style={{ background: `linear-gradient(to right, ${color} ${value * 100}%, hsl(var(--muted)) ${value * 100}%)`, accentColor: color, }} aria-label={`${label} share: ${(value * 100).toFixed(0)}%`} />
{(value * 100).toFixed(0)}%
); }