Chapter 10: Coordinate System, Machine Settings & Symmetry Rules
Before writing custom cuts or math expressions, you need a rock-solid picture of three fundamentals: how the interpreter steps through your script, how the 3D coordinate system is oriented, and how gear teeth and symmetry modifiers map to angles around the dop.
1. Sequential Execution: Cut Order Matters!
Both the FSL and Lua interpreters act like a patient master cutter sitting at a physical machine: they start with a solid uncut block of rough crystal (centered at (0, 0, 0)) and execute your statements strictly from top to bottom.
[!IMPORTANT] You Can Only Aim at Corners That Already Exist on the Stone If Tier
C2tries to meetmp(C1)before TierC1has been cut, the interpreter will stop and report an error becauseC1does not exist on the polyhedron yet! Always cut your foundation tiers first, then cut the tiers that reference their corners.
Run the interactive example below to see how four sequential cuts carve a raw block into a finished stone—and try switching between FSL and Lua:
name = "Sequential Cutting Order"
ri = 1.76
gear = 96
size = 1.0
girdle = Vector(0, 0, 0.04)
// 1. Cut P1 first (meets at the bottom center point 0, 0, -1)
P1 0 @ 43.0 : cp() x8
// 2. Cut G1 second (creates the 8 corners where P1 meets G1)
G1 0 @ 90.0 : size x8
// 3. Now C1 can safely reference mp(P1, G1)!
C1 0 @ 36.0 : mp(P1, G1) + girdle x8
// 4. Finally, T references the inner slope of C1
T 0 @ 0.0 : 0.35 x1
-- lua script
name("Sequential Cutting Order")
ri(1.76)
gear(96)
local size = 1.0
local girdle = Point(0, 0, 0.04)
-- 1. Cut P1 first
TierAP("P1", 0, 43.0, cp(), "x8")
-- 2. Cut G1 second
TierAD("G1", 0, 90.0, size, "x8")
-- 3. Now C1 can safely reference mp("P1", "G1")!
TierAP("C1", 0, 36.0, mp("P1", "G1"):add(girdle), "x8")
-- 4. Finally, cut the flat Table
TierAD("T", 0, 0.0, 0.35, "x1")
2. The 3D Right-Handed Coordinate Frame
When you use explicit Point(x, y, z) or Vector(x, y, z) coordinates, how are the X, Y, and Z axes oriented inside the stone?
- Origin
(0, 0, 0): The geometric center of the uncut blank, typically sitting in the plane of the Pavilion girdle equator (z = 0). +ZAxis (Up/ Crown): Points straight up through the center of the Table. The Crown centerpoint is(0, 0, +1).-ZAxis (Down/ Pavilion): Points straight down through the Pavilion culet. Whencp()is used on a Pavilion tier (P1,PF1), it resolves to(0, 0, -1).+YAxis (Index 0 / 96): Points toward the top of the Crown/Pavilion diagram (12 o'clock).+XAxis (Index 24on a 96-gear): Points to the right (3 o'clock) when clockwise indexing (cw = true, the default) is active.- Standard Radius (
size = 1.0): By convention, preforms normalize the stone's narrow width radius to1.0(meaning a total stone width of2.0units from-1.0to+1.0). Therefore, agirdlethickness of0.03represents0.03 / 2.0 = 1.5%(or3%of radius).
3. Project & Machine Settings Reference
Place your stone metadata and machine configuration at the top of your script:
| Setting | FSL Example | Lua Example | Purpose & Default |
|---|---|---|---|
name | name = "Royal Cushion" | name("Royal Cushion") | Title displayed in the 3D Studio, file browser, and printed spec sheet. |
ri | ri = 1.76 | ri(1.76) | Material refractive index (1.54 default). Also readable as a numeric value (ri in FSL, ri() in Lua) inside formulas! |
gear | gear = 96 | gear(96) | Index gear tooth count (96 default; supports 32, 64, 72, 80, 96, 120, etc.). Can even be changed mid-script! |
cw | cw = true | cw(true) | Gear tooth direction: true (default) steps clockwise around the diagram; false steps counter-clockwise. |
color | color = "#38bdf8" | color("#38bdf8") | Hex body color used by the spectral raytracer and path tracer. |
absorption | absorption = 1.4 | absorption(1.4) | Beer-Lambert light absorption multiplier (1.0 default; higher values produce deeper, richer saturation). |
cube | cube = 5.0 | cube(5.0) | Resets the starting uncut rough blank to a cube of half-size 5.0 (essential for tall cuts like Briolettes that extend beyond the default ±2.0 blank). |
girdle | girdle = Vector(0, 0, 0.03) | girdle = Point(0, 0, 0.03) | Vertical offset vector added to the first Crown tier (+ girdle) to establish girdle thickness. |
notes | notes = "Cut in Sri Lankan sapphire" | notes("Cut in Sri Lankan sapphire") | Free-form cutter notes included on the printable sheet. |
tags | tags = "cushion, sapphire" | tags("cushion, sapphire") | Searchable keywords for the Open Design library. |
4. How Symmetry & Mirror Modifiers Work (xN, m M, xxN, and Lists)
Once you specify a tier's Base Index (IDX), you can replicate that facet around the gear in four ways:
A. Rotational Symmetry (xN in FSL / "xN" in Lua)
Divides the gear into N equal steps of Gear / N teeth starting at IDX:
P1 0 @ 41.5 : cp() x8on a96gear steps by96 / 8 = 12teeth:- Cuts teeth:
0 (96), 12, 24, 36, 48, 60, 72, 84(8 facets).
- Cuts teeth:
C3 6 @ 22.0 : mp(C1) x8starts at tooth6and steps by12:- Cuts teeth:
6, 18, 30, 42, 54, 66, 78, 90(8 facets).
- Cuts teeth:
B. Rotational + Mirror Delta Symmetry (xN m M in FSL / "xN m M" in Lua)
In IDX @ angle : target xN m M, your base index IDX is the mirror axis (center)—not a tooth that gets cut itself—and the number M after m is the ± delta index (±M teeth) added to and subtracted from each of the N rotational symmetry axes (axis - M and axis + M):
P2 0 @ 43.0 : gp() x8 m 3on a96gear:- Symmetry axes sit at
0 (96), 12, 24, 36, 48, 60, 72, 84. - Delta index
m 3cuts±3teeth around each axis (0 - 3 = 93and0 + 3 = 3,12 - 3 = 9and12 + 3 = 15, etc.):3, 9, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, 81, 87, 93(16 facets).
- Symmetry axes sit at
P2 6 @ 42.2 : mp(P1) x8 m 2on a96gear:- Symmetry axes sit at
6, 18, 30, 42, 54, 66, 78, 90. - Delta index
m 2cuts±2teeth around each axis (6 - 2 = 4and6 + 2 = 8, etc.):4, 8, 16, 20, 28, 32, 40, 44, 52, 56, 64, 68, 76, 80, 88, 92(16 facets).
- Symmetry axes sit at
C. Zero-Axis Mirror Shorthand (xxN in FSL / "xxN" in Lua)
Unlike xN m M (where IDX is the un-cut mirror center and M is the ± delta index), in IDX @ angle : target xxN your base index IDX is an actual cut tooth, and xxN repeats IDX N times around the gear while reflecting every cut across index 0 (Gear - tooth, i.e., 0 - IDX and 0 + IDX).
Because xxN always mirrors across index 0, writing M @ angle : target xxN is a concise shorthand for centering the mirror axis at 0 with a ±M delta index (0 @ angle : target xN m M):
P2 3 @ 43.0 : gp() xx8is 100% equivalent toP2 0 @ 43.0 : gp() x8 m 3(andP2 6 @ 43.0 : gp() x8 m 3), cutting0 ± 3 = 93, 3repeated 8 times:3, 9, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, 81, 87, 93.P2 4 @ 42.2 : mp(P1) xx8is 100% equivalent toP2 0 @ 42.2 : mp(P1) x8 m 4(orP2 6 @ 42.2 : mp(P1) x8 m 2), cutting0 ± 4repeated 8 times:4, 8, 16, 20, 28, 32, 40, 44, 52, 56, 64, 68, 76, 80, 88, 92.
[!IMPORTANT] Don't Confuse
3 @ ... xx8with3 @ ... x8 m 3! Remember that the number aftermis the±delta index relative toIDX, not an absolute tooth index:
P2 3 @ 43.0 : gp() xx8(=P2 0 @ 43.0 : gp() x8 m 3) mirrors across0(0 ± 3), cutting3, 9, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, 81, 87, 93.P2 3 @ 43.0 : gp() x8 m 3places the mirror center at3and applies a±3delta (3 - 3 = 0and3 + 3 = 6), cutting0, 6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90(shifted by 3 teeth!).
D. Explicit Index Arrays ([i1, i2, ...] in FSL / {i1, i2, ...} in Lua)
Need an asymmetric cut, a heart cleft, or a custom subset of teeth? Pass an array of tooth numbers as the index!
P1 [0, 24, 48, 72] @ 42.0 : cp()(orTierAP("P1", {0, 24, 48, 72}, 42.0, cp())in Lua) cuts those exact 4 teeth.
E. Symmetry Inheritance (Omitting xN on Consecutive Tiers)
If you omit the symmetry modifier on a tier, ProFacet automatically reuses the symmetry and mirror settings from the previous tier! That is why in a simple step cut, writing x4 on P1 lets G1 and C1 inherit x4 automatically if omitted—though writing x4 or x8 explicitly on every tier is great practice for clarity.
5. Interactive Playground: Test All Four Symmetry Forms Live
Click the tier chips P1, P2, C1, and C2 in the playground below to see how x8, x8 m 3, xx8, and explicit index arrays [0, 24, 48, 72] place facets around the 96-tooth gear:
name = "Symmetry Forms Showcase"
ri = 1.76
gear = 96
color = "#f59e0b"
// 1. Mirrored 8-fold symmetry (16 facets at 3, 9, 15, 21...)
P1 3 @ 43.0 : cp() xx8
G1 3 @ 90.0 : size xx8
// 2. Rotational 8-fold symmetry (8 facets at 0, 12, 24, 36, 48, 60, 72, 84)
P2 0 @ 41.5 : gp() x8
// 3. Rotational + mirror delta symmetry (0 ± 3 -> same 16 teeth as 3 ... xx8!)
C1 0 @ 42.0 : mp(P1, P2) + girdle x8 m 3
// 4. Explicit tooth array for 4 cardinal bezel facets + 4 offset facets
C2 [0, 24, 48, 72] @ 34.0 : gp()
C3 [12, 36, 60, 84] @ 34.0 : gp()
C4 6 @ 21.5 : mp(C1) x8
T 0 @ 0.0 : mp(C2) x1
-- lua script
name("Symmetry Forms Showcase")
ri(1.76)
gear(96)
color("#f59e0b")
-- 1. Mirrored 8-fold symmetry (16 facets)
TierAP("P1", 3, 43.0, cp(), "xx8")
TierAD("G1", 3, 90.0, size, "xx8")
-- 2. Rotational 8-fold symmetry (8 facets)
TierAP("P2", 0, 41.5, gp(), "x8")
-- 3. Rotational + mirror delta symmetry (0 ± 3 -> same 16 teeth as 3 ... xx8!)
TierAP("C1", 0, 42.0, mp("P1", "P2"):add(girdle), "x8 m 3")
-- 4. Explicit tooth table for 4 cardinal bezel facets + 4 offset facets
TierAP("C2", {0, 24, 48, 72}, 34.0, gp())
TierAP("C3", {12, 36, 60, 84}, 34.0, gp())
TierAP("C4", 6, 21.5, mp("C1"), "x8")
TierAP("T", 0, 0.0, mp("C2"), "x1")
Next, let’s learn the three distinct geometric styles for aiming a facet cut—Angle + Depth, Angle + Meetpoint, and Point-Pair—in Chapter 11: Cutting Facets & Tiers — The Three Design Styles.