Summary
Add an <Arc> React component to wrap Two.js's Arc class from the extras module. This will enable developers to create open arc shapes (partial circles/ellipses) for use in pie charts, progress indicators, and circular UI elements.
Motivation
Two.js provides an Arc class in extras/jsm/arc.js that creates open arc shapes (as opposed to ArcSegment which creates closed pie-slice shapes). This is useful for:
- Progress indicators (loading circles)
- Pie charts and donut charts
- Circular gauges and meters
- Partial circle decorations
- Arc-based animations
Currently, react-two.js includes ArcSegment but not Arc, leaving a gap for developers who need open arc shapes.
Arc vs ArcSegment
Arc (from extras):
- Open arc shape (no filled center)
- Creates a curved line from startAngle to endAngle
- Like drawing part of a circle's outline
- Useful for: progress indicators, gauges, open curves
ArcSegment (core, already in react-two.js):
- Closed pie-slice shape
- Creates a filled wedge with center point
- Like a slice of pizza
- Useful for: pie charts, radar charts, filled sections
// Two.js Arc example
import { Arc } from 'two.js/extras/jsm/arc.js';
const arc = new Arc(0, 0, 100, 100, 0, Math.PI);
// Creates an open semicircle arc
Proposed API
Component Signature
interface ArcProps {
// Position
x?: number;
y?: number;
// Dimensions
width?: number; // Horizontal diameter
height?: number; // Vertical diameter
// Arc angles (in radians)
startAngle?: number; // Starting angle (default: 0)
endAngle?: number; // Ending angle (default: 2π)
// Path properties
resolution?: number; // Number of vertices (default: 4)
curved?: boolean; // Smooth curve (default: true)
// Styling (inherited from Path)
stroke?: string;
linewidth?: number;
fill?: string; // Usually 'transparent' for arcs
cap?: 'butt' | 'round' | 'square';
join?: 'miter' | 'round' | 'bevel';
opacity?: number;
visible?: boolean;
// Transform
rotation?: number;
scale?: number;
}
export type RefArc = Arc; // From two.js/extras/jsm/arc
export const Arc: React.ForwardRefExoticComponent<
ArcProps & React.RefAttributes<RefArc>
>;
Usage Examples
Basic Arc
import { Canvas, Arc } from 'react-two.js';
function BasicArc() {
return (
<Canvas width={400} height={400}>
<Arc
x={200}
y={200}
width={100}
height={100}
startAngle={0}
endAngle={Math.PI}
stroke="blue"
linewidth={3}
fill="transparent"
/>
</Canvas>
);
}
Progress Indicator
function ProgressIndicator({ progress }: { progress: number }) {
// progress: 0 to 1
const startAngle = -Math.PI / 2; // Start at top
const endAngle = startAngle + (Math.PI * 2 * progress);
return (
<>
{/* Background arc */}
<Arc
x={100}
y={100}
width={80}
height={80}
startAngle={0}
endAngle={Math.PI * 2}
stroke="lightgray"
linewidth={8}
/>
{/* Progress arc */}
<Arc
x={100}
y={100}
width={80}
height={80}
startAngle={startAngle}
endAngle={endAngle}
stroke="blue"
linewidth={8}
cap="round"
/>
</>
);
}
Animated Loading Spinner
function LoadingSpinner() {
const arcRef = useRef<RefArc>(null);
useFrame((elapsed) => {
if (arcRef.current) {
arcRef.current.rotation = elapsed * 2;
}
});
return (
<Arc
ref={arcRef}
x={200}
y={200}
width={60}
height={60}
startAngle={0}
endAngle={Math.PI * 1.5}
stroke="purple"
linewidth={4}
cap="round"
/>
);
}
Gauge/Meter
function Gauge({ value, max }: { value: number; max: number }) {
const startAngle = Math.PI * 0.75; // Start at bottom-left
const endAngle = startAngle + (Math.PI * 1.5 * (value / max));
return (
<>
{/* Gauge background */}
<Arc
x={150}
y={150}
width={120}
height={120}
startAngle={Math.PI * 0.75}
endAngle={Math.PI * 2.25}
stroke="#eee"
linewidth={10}
/>
{/* Gauge value */}
<Arc
x={150}
y={150}
width={120}
height={120}
startAngle={startAngle}
endAngle={endAngle}
stroke="green"
linewidth={10}
cap="round"
/>
{/* Center text */}
<Text
value={`${value}/${max}`}
x={150}
y={150}
size={20}
alignment="center"
/>
</>
);
}
Elliptical Arc
function EllipticalArc() {
return (
<Arc
x={200}
y={150}
width={150} // Wide
height={80} // Narrow
startAngle={0}
endAngle={Math.PI}
stroke="red"
linewidth={2}
/>
);
}
Multiple Arcs (Donut Chart Alternative)
function ArcGallery() {
return (
<>
{[0, 1, 2, 3].map((i) => (
<Arc
key={i}
x={200}
y={200}
width={100}
height={100}
startAngle={(Math.PI / 2) * i}
endAngle={(Math.PI / 2) * (i + 0.8)}
stroke={`hsl(${i * 90}, 70%, 50%)`}
linewidth={20}
cap="round"
/>
))}
</>
);
}
Implementation Phases
Phase 1: Core Component Structure
Files: lib/Arc.tsx (new file)
Deliverable: Basic Arc component skeleton with TypeScript types
Phase 2: Arc Instance Management
Files: lib/Arc.tsx
Deliverable: Arc instances created and added to scene
Phase 3: Props Handling & Updates
Files: lib/Arc.tsx
Deliverable: Reactive prop updates on Arc component
Phase 4: Ref Forwarding
Files: lib/Arc.tsx
Deliverable: Working ref forwarding for imperative access
Phase 5: Integration & Export
Files: lib/main.ts
Deliverable: Arc component available in public API
Phase 6: Testing
Files: lib/__tests__/Arc.test.tsx (new file)
Deliverable: Comprehensive test coverage
Phase 7: Documentation & Examples
Files: README.md, src/App.tsx, documentation site
Deliverable: Complete documentation with examples
Technical Considerations
Arc Class Implementation
The Arc class (from Two.js extras):
class Arc extends Path {
constructor(x, y, width, height, startAngle, endAngle, resolution) {
// Creates vertices based on angles
// Curved by default
// Open path (not closed)
}
// Properties: width, height, startAngle, endAngle
// Inherits: stroke, linewidth, cap, join, etc. from Path
}
Key characteristics:
- Extends Two.Path (not a primitive)
- Creates vertices based on angle range
- Automatically curved for smooth arcs
- Open path (no automatic closure)
- Resolution controls vertex count (higher = smoother)
Design Decisions
- Component approach: Matches existing shape component patterns
- Extras integration: First component from Two.js extras module
- Angle units: Use radians (Two.js convention)
- Default curved: Arcs are typically curved (can be overridden)
- Stroke-focused: Arcs typically use stroke, not fill
- Ref forwarding: Consistent with other shape components
- TypeScript: Full type safety for all props
Arc vs ArcSegment
| Feature |
Arc |
ArcSegment |
| Shape |
Open arc line |
Closed pie slice |
| Fill |
Typically transparent |
Can be filled |
| Use Case |
Progress bars, gauges |
Pie charts, radar |
| Closure |
Open path |
Closed path |
| Module |
extras/jsm/arc |
Core shapes |
| Available |
❌ Missing |
✅ Exists |
Performance Considerations
- Arc vertices calculated based on resolution
- Higher resolution = smoother but more vertices
- Update performance similar to Path component
- Angle changes recalculate vertices
- Consider memoizing angle calculations for animations
Importing from Extras
This will be the first component importing from Two.js extras:
import { Arc } from 'two.js/extras/jsm/arc.js';
Considerations:
- Verify extras are included in Two.js package
- Check bundle size impact
- Ensure tree-shaking works with extras
- Test across different module systems
Alternative Approaches Considered
1. Enhance ArcSegment with closed prop:
<ArcSegment closed={false} />
Pros: No new component
Cons: Different underlying class, confusing API, different properties
Decision: Separate component is clearer
2. Generic CurvedPath component:
<CurvedPath vertices={...} closed={false} />
Pros: More flexible, covers many use cases
Cons: Too low-level, loses Arc-specific conveniences
Decision: Dedicated Arc component is more user-friendly
3. Path with arc helper:
<Path vertices={generateArcVertices(0, Math.PI)} />
Pros: Uses existing component
Cons: Manual vertex generation, loses Arc class benefits
Decision: Native Arc component is simpler
Resources
Success Criteria
Labels: enhancement, feature request, component, shapes
Milestone: v0.3.0
Summary
Add an
<Arc>React component to wrap Two.js'sArcclass from the extras module. This will enable developers to create open arc shapes (partial circles/ellipses) for use in pie charts, progress indicators, and circular UI elements.Motivation
Two.js provides an
Arcclass inextras/jsm/arc.jsthat creates open arc shapes (as opposed toArcSegmentwhich creates closed pie-slice shapes). This is useful for:Currently, react-two.js includes
ArcSegmentbut notArc, leaving a gap for developers who need open arc shapes.Arc vs ArcSegment
Arc (from extras):
ArcSegment (core, already in react-two.js):
Proposed API
Component Signature
Usage Examples
Basic Arc
Progress Indicator
Animated Loading Spinner
Gauge/Meter
Elliptical Arc
Multiple Arcs (Donut Chart Alternative)
Implementation Phases
Phase 1: Core Component Structure
Files:
lib/Arc.tsx(new file)Arc.tsxwith React component boilerplatetwo.js/extras/jsm/arc.jsArcPropsTypeScript interfaceRefArctypeforwardRefuseTwo()contextDeliverable: Basic Arc component skeleton with TypeScript types
Phase 2: Arc Instance Management
Files:
lib/Arc.tsxuseLayoutEffectfor Arc creation:Deliverable: Arc instances created and added to scene
Phase 3: Props Handling & Updates
Files:
lib/Arc.tsxuseEffectfor property updates:Deliverable: Reactive prop updates on Arc component
Phase 4: Ref Forwarding
Files:
lib/Arc.tsxuseImperativeHandlefor ref forwardingDeliverable: Working ref forwarding for imperative access
Phase 5: Integration & Export
Files:
lib/main.tsArccomponent fromlib/main.tsRefArctype fromlib/main.tsDeliverable: Arc component available in public API
Phase 6: Testing
Files:
lib/__tests__/Arc.test.tsx(new file)Deliverable: Comprehensive test coverage
Phase 7: Documentation & Examples
Files:
README.md,src/App.tsx, documentation siteArccomponent to README shape listDeliverable: Complete documentation with examples
Technical Considerations
Arc Class Implementation
The Arc class (from Two.js extras):
Key characteristics:
Design Decisions
Arc vs ArcSegment
Performance Considerations
Importing from Extras
This will be the first component importing from Two.js extras:
Considerations:
Alternative Approaches Considered
1. Enhance ArcSegment with
closedprop:Pros: No new component
Cons: Different underlying class, confusing API, different properties
Decision: Separate component is clearer
2. Generic CurvedPath component:
Pros: More flexible, covers many use cases
Cons: Too low-level, loses Arc-specific conveniences
Decision: Dedicated Arc component is more user-friendly
3. Path with arc helper:
Pros: Uses existing component
Cons: Manual vertex generation, loses Arc class benefits
Decision: Native Arc component is simpler
Resources
Success Criteria
<Arc>component successfully creates arc shapesLabels: enhancement, feature request, component, shapes
Milestone: v0.3.0