Here’s the plan for the curve text feature (Designer side only):

1. Data Model Update

Extend your rotations state to include a curve value:

type TextShape = {
  rotation: number;
  curve: number; // 0 = straight, >0 = arc up, <0 = arc down
};


So instead of only rotations, you track textShapes[id] = { rotation, curve }.

2. SVG Arc Generator

We’ll create a helper that generates a smooth arc path:

function buildArcPath(x: number, y: number, width: number, curve: number) {
  // curve is sagitta: how "tall" the arc bows (positive = up, negative = down)
  const x0 = x - width / 2;
  const x1 = x + width / 2;
  const y0 = y;
  const y1 = y;

  const arcFlag = curve > 0 ? 0 : 1;
  const rx = Math.abs(curve) + width / 2;

  return `M ${x0},${y0} A ${rx},${rx} 0 0,${arcFlag} ${x1},${y1}`;
}


This creates the path string for <textPath>.

3. Rendering Curved Text

If curve !== 0 → render text along a <textPath>:

<svg>
  <defs>
    <path id={`arc-${id}`} d={buildArcPath(cx, cy, 300, curve)} />
  </defs>
  <text style={{ fontFamily: fonts[id], fontSize: 24 }}>
    <textPath href={`#arc-${id}`} startOffset="50%" textAnchor="middle">
      {values[id]}
    </textPath>
  </text>
</svg>


If curve === 0, fallback to regular <text> with transform="rotate(...)".

4. Curve Slider (Designer Controls)

Right under each rotation slider, add a Curve slider:

<div>
  <div className="flex items-center justify-between text-sm text-gray-600 mb-1">
    <span>Curve</span>
    <span>{textShapes[id].curve}</span>
  </div>
  <input
    type="range"
    min={-200}
    max={200}
    step={5}
    value={textShapes[id].curve}
    onChange={(e) =>
      setTextShapes((prev) => ({
        ...prev,
        [id]: { ...prev[id], curve: Number(e.target.value) }
      }))
    }
    className="w-full"
  />
  <div className="flex justify-between text-xs text-gray-400">
    <span>Arc Down</span>
    <span>Straight</span>
    <span>Arc Up</span>
  </div>
</div>

5. End-to-End Flow

Admin → sets base geometry (no curve).

Designer → can rotate and curve text with sliders.

If curve ≠ 0, switch render to <textPath>.

Works seamlessly with your existing Firebase template store.