Skip to content

Commit ef36472

Browse files
committed
feat: circularArray
1 parent 3cdb10e commit ef36472

5 files changed

Lines changed: 480 additions & 15 deletions

File tree

CLAUDE.md

Lines changed: 137 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,13 @@ npm run export --silent -- Box > box.stl
122122

123123
```typescript
124124
Solid.cube(width, height, depth, { color? })
125+
Solid.roundedBox(width, height, depth, { color?, radius?, segments? })
125126
Solid.cylinder(radius, height, { color?, angle? }) // angle in degrees
126127
Solid.sphere(radius, { color?, angle? })
127128
Solid.cone(radius, height, { color?, angle? })
128129
Solid.prism(sides, radius, height, { color?, angle? })
129130
Solid.trianglePrism(radius, height, { color? })
131+
Solid.text(text, { color?, size?, height?, curveSegments?, bevelEnabled? })
130132
```
131133

132134
### Custom Profile Prisms
@@ -159,6 +161,77 @@ Solid.revolutionSolidFromPath([straight(5), curve(2, 90), ...], { angle?, color?
159161

160162
**Profile coordinates:** X=radius from center, Y=height, rotates around Y-axis
161163

164+
### 3D Text Extrusion
165+
166+
Create 3D text shapes with customizable size and extrusion depth:
167+
168+
```typescript
169+
// Simple text
170+
const label = Solid.text('Hello', { size: 10, height: 2, color: 'blue' });
171+
172+
// Text with bevel (rounded edges)
173+
const logo = Solid.text('LOGO', { size: 15, height: 3, bevelEnabled: true, color: 'gold' });
174+
175+
// Text as cutter for engraving
176+
const plate = Solid.cube(50, 20, 5, { color: 'gray' });
177+
const text = Solid.text('ENGRAVED', { size: 4, height: 10, color: 'gray' });
178+
const engraved = Solid.SUBTRACT(plate, text);
179+
180+
// Embossed text (raised text on surface)
181+
const base = Solid.cube(40, 30, 3, { color: 'gray' });
182+
const embossText = Solid.text('LOGO', { size: 6, height: 2, color: 'gold' }).move({ y: 3 }); // Position on top of base
183+
const embossed = Solid.UNION(base, embossText);
184+
```
185+
186+
**Text Parameters:**
187+
188+
- `text`: The string to render (required, cannot be empty)
189+
- `size`: Font size (default: 10)
190+
- `height`: Extrusion depth along Y-axis (default: 2)
191+
- `curveSegments`: Smoothness of curves (default: 12, lower=faster but blockier)
192+
- `bevelEnabled`: Add rounded edges to text (default: false)
193+
- `color`: Color of the text geometry
194+
195+
**Important Notes:**
196+
197+
- Uses Helvetiker Regular font (built-in)
198+
- Text is automatically centered on XZ plane and aligned to Y=0
199+
- For engraving/embossing, make text height > target depth to ensure complete cut
200+
- **Performance warning:** Long text (>10 characters) or high curveSegments can slow CSG operations
201+
- For better performance with long text, reduce `curveSegments` to 8
202+
203+
### Rounded Box
204+
205+
Create boxes with filleted/rounded edges:
206+
207+
```typescript
208+
// Basic rounded box with auto-calculated radius (10% of smallest dimension)
209+
const box = Solid.roundedBox(10, 10, 10, { color: 'teal' });
210+
211+
// Custom radius
212+
const customBox = Solid.roundedBox(20, 15, 10, { color: 'blue', radius: 2 });
213+
214+
// High quality rounding (more segments)
215+
const smoothBox = Solid.roundedBox(10, 10, 10, { color: 'red', radius: 1.5, segments: 4 });
216+
```
217+
218+
**Rounded Box Parameters:**
219+
220+
- `width`, `height`, `depth`: Box dimensions (required, must be positive)
221+
- `radius`: Corner radius (default: 10% of smallest dimension)
222+
- Must be ≤ half of smallest dimension
223+
- Larger radius = more rounded corners
224+
- `segments`: Rounding quality (default: 2)
225+
- Higher values = smoother but more geometry
226+
- 2 is sufficient for most cases
227+
228+
**Use Cases:**
229+
230+
- Mechanical parts with filleted edges
231+
- Product design and prototyping
232+
- Realistic objects (boxes are rarely sharp-edged in real life)
233+
- Ergonomic designs
234+
162235
## Import Capabilities
163236

164237
### STL Import
@@ -295,6 +368,67 @@ Solid.GRID_XY(brick, { cols: 10, rows: 5, spacing: [1, 0.5] }); // 2D
295368
Solid.GRID_XYZ(brick, { cols: 5, rows: 5, levels: 3, spacing: [1, 1, 2] }); // 3D
296369
```
297370

371+
### Circular Arrays
372+
373+
Arrange solids in circular/radial patterns (polar arrays):
374+
375+
```typescript
376+
// Gear teeth - elements face outward by default
377+
// IMPORTANT: Element must extend in +X direction to face outward when rotated
378+
// Width (X) > depth (Z) makes tooth point radially
379+
const disk = Solid.cylinder(15, 8, { color: 'gray' }).align('bottom');
380+
const tooth = Solid.cube(3, 10, 2, { color: 'gray' }) // 3 wide (X), 2 deep (Z)
381+
.center({ x: true, z: true })
382+
.align('bottom')
383+
.move({ y: 8 }); // Position on top of disk
384+
const teeth = Solid.ARRAY_CIRCULAR(tooth, { count: 24, radius: 17 });
385+
const gear = Solid.UNION(disk, teeth);
386+
387+
// Bolt holes - no rotation needed for holes
388+
const hole = Solid.cylinder(2, 10, { color: 'blue' }).setNegative();
389+
const pattern = Solid.ARRAY_CIRCULAR(hole, { count: 8, radius: 20, rotateElements: false });
390+
391+
// Half circle (amphitheater seating)
392+
const seat = Solid.cube(2, 1, 2, { color: 'red' });
393+
const seating = Solid.ARRAY_CIRCULAR(seat, { count: 15, radius: 25, startAngle: 0, endAngle: 180 });
394+
395+
// Wheel spokes from center (radius = 0, just rotation)
396+
const spoke = Solid.cube(1, 20, 2, { color: 'silver' }).center({ x: true, z: true });
397+
const spokes = Solid.ARRAY_CIRCULAR(spoke, { count: 12, radius: 0 });
398+
399+
// Decorative rosette with multiple layers
400+
const orb = Solid.sphere(2, { color: 'gold' });
401+
const innerRing = Solid.ARRAY_CIRCULAR(orb, { count: 8, radius: 8, rotateElements: false });
402+
const outerRing = Solid.ARRAY_CIRCULAR(orb, { count: 16, radius: 15, rotateElements: false });
403+
const rosette = Solid.UNION(innerRing, outerRing);
404+
```
405+
406+
**Parameters:**
407+
408+
- `count`: Number of copies (required, must be >= 1)
409+
- `radius`: Radius of circular arrangement (required, must be > 0)
410+
- `startAngle`: Starting angle in degrees (default: 0)
411+
- `endAngle`: Ending angle in degrees (default: 360)
412+
- `rotateElements`: Rotate elements to face outward (default: true)
413+
414+
**Key Behaviors:**
415+
416+
- Elements distributed evenly in XZ plane (horizontal circle around Y-axis)
417+
- By default, elements rotate to face outward (like gear teeth)
418+
- Set `rotateElements: false` for spheres, holes, or decorative elements
419+
- Partial circles: use `startAngle`/`endAngle` for arcs (e.g., 0° to 180° = half circle)
420+
- Elements evenly spaced within angular range (startAngle included, endAngle excluded for full circles)
421+
- **Y position preserved**: Elements maintain their vertical (Y) position, allowing layered circular patterns
422+
- **Element orientation**: For radial elements, create them so they extend in the +X direction. When rotated, they'll face outward correctly. Example: for a tooth pointing outward, use `cube(3, 10, 2)` not `cube(2, 10, 3)` - width > depth
423+
- **IMPORTANT**: Center elements with `.center({ x: true, z: true })` before passing to ARRAY_CIRCULAR. The `radius` parameter handles X/Z positioning, but you can use `.move({ y })` for vertical placement
424+
425+
**Common Use Cases:**
426+
427+
- Mechanical: Gear teeth, splines, bolt holes, heat sink fins
428+
- Architectural: Columns, amphitheater seating, circular windows
429+
- Decorative: Medallions, rosettes, clock markers, mandalas
430+
- Functional: Turbine blades, fan blades, ventilation slots, spokes
431+
298432
## Performance - Caching
299433

300434
```typescript
@@ -325,7 +459,7 @@ const w3 = Wall(30); // Different params, new computation
325459

326460
### Factory Methods
327461

328-
`cube(w,h,d,opts)`, `cylinder(r,h,opts)`, `sphere(r,opts)`, `cone(r,h,opts)`, `prism(sides,r,h,opts)`, `trianglePrism(r,h,opts)`
462+
`cube(w,h,d,opts)`, `roundedBox(w,h,d,opts)`, `cylinder(r,h,opts)`, `sphere(r,opts)`, `cone(r,h,opts)`, `prism(sides,r,h,opts)`, `trianglePrism(r,h,opts)`, `text(text,opts)`
329463

330464
### Import Methods
331465

@@ -351,9 +485,9 @@ const w3 = Wall(30); // Different params, new computation
351485

352486
`SUBTRACT(src,...others)`, `UNION(src,...others)`, `INTERSECT(a,b)`, `MERGE(solids[])`
353487

354-
### Grids (static, immutable)
488+
### Grids & Arrays (static, immutable)
355489

356-
`GRID_X(solid,{cols,spacing?})`, `GRID_XY(solid,{cols,rows,spacing?})`, `GRID_XYZ(solid,{cols,rows,levels,spacing?})`
490+
`GRID_X(solid,{cols,spacing?})`, `GRID_XY(solid,{cols,rows,spacing?})`, `GRID_XYZ(solid,{cols,rows,levels,spacing?})`, `ARRAY_CIRCULAR(solid,{count,radius,startAngle?,endAngle?,rotateElements?})`
357491

358492
### Alignment (chainable)
359493

plan.MD

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,7 @@ Analysis of potential improvements and missing features for the CSG Builder proj
44

55
## 🟡 MEDIUM PRIORITY (Quality of Life)
66

7-
### 1. Missing Primitives
8-
9-
- **Rounded Box** (filleted edges - very common)
10-
- **Text Extrusion** (3D text via Three.js TextGeometry)
11-
12-
### 2. Missing CSG Operations
7+
### 1. Missing CSG Operations
138

149
- **MIRROR** - Reflect across planes
1510
- **CHAMFER/FILLET** - Edge rounding (critical for manufacturing)

0 commit comments

Comments
 (0)