Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Chapter 10: Coordinate System, Machine Settings & Symmetry Rules

PART II · CHAPTER 10 Sequential Execution · 3D Coordinate Axes · Machine Metadata · Rotational & Mirror Symmetry

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 C2 tries to meet mp(C1) before Tier C1 has been cut, the interpreter will stop and report an error because C1 does 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?

+Y (Tooth 0 / 96 · 12 o'clock) −Y (Tooth 48 · 6 o'clock) +X (Tooth 24 · cw=true) −X (Tooth 72) (0, 0, 0)

VERTICAL Z-AXIS +Z → Crown Table z = 0 (Girdle) −Z → Pavilion Culet
  • Origin (0, 0, 0): The geometric center of the uncut blank, typically sitting in the plane of the Pavilion girdle equator (z = 0).
  • +Z Axis (Up / Crown): Points straight up through the center of the Table. The Crown centerpoint is (0, 0, +1).
  • -Z Axis (Down / Pavilion): Points straight down through the Pavilion culet. When cp() is used on a Pavilion tier (P1, PF1), it resolves to (0, 0, -1).
  • +Y Axis (Index 0 / 96): Points toward the top of the Crown/Pavilion diagram (12 o'clock).
  • +X Axis (Index 24 on 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 to 1.0 (meaning a total stone width of 2.0 units from -1.0 to +1.0). Therefore, a girdle thickness of 0.03 represents 0.03 / 2.0 = 1.5% (or 3% of radius).

3. Project & Machine Settings Reference

Place your stone metadata and machine configuration at the top of your script:

SettingFSL ExampleLua ExamplePurpose & Default
namename = "Royal Cushion"name("Royal Cushion")Title displayed in the 3D Studio, file browser, and printed spec sheet.
riri = 1.76ri(1.76)Material refractive index (1.54 default). Also readable as a numeric value (ri in FSL, ri() in Lua) inside formulas!
geargear = 96gear(96)Index gear tooth count (96 default; supports 32, 64, 72, 80, 96, 120, etc.). Can even be changed mid-script!
cwcw = truecw(true)Gear tooth direction: true (default) steps clockwise around the diagram; false steps counter-clockwise.
colorcolor = "#38bdf8"color("#38bdf8")Hex body color used by the spectral raytracer and path tracer.
absorptionabsorption = 1.4absorption(1.4)Beer-Lambert light absorption multiplier (1.0 default; higher values produce deeper, richer saturation).
cubecube = 5.0cube(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).
girdlegirdle = 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.
notesnotes = "Cut in Sri Lankan sapphire"notes("Cut in Sri Lankan sapphire")Free-form cutter notes included on the printable sheet.
tagstags = "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() x8 on a 96 gear steps by 96 / 8 = 12 teeth:
    • Cuts teeth: 0 (96), 12, 24, 36, 48, 60, 72, 84 (8 facets).
  • C3 6 @ 22.0 : mp(C1) x8 starts at tooth 6 and steps by 12:
    • Cuts teeth: 6, 18, 30, 42, 54, 66, 78, 90 (8 facets).

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 3 on a 96 gear:
    • Symmetry axes sit at 0 (96), 12, 24, 36, 48, 60, 72, 84.
    • Delta index m 3 cuts ±3 teeth around each axis (0 - 3 = 93 and 0 + 3 = 3, 12 - 3 = 9 and 12 + 3 = 15, etc.): 3, 9, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, 81, 87, 93 (16 facets).
  • P2 6 @ 42.2 : mp(P1) x8 m 2 on a 96 gear:
    • Symmetry axes sit at 6, 18, 30, 42, 54, 66, 78, 90.
    • Delta index m 2 cuts ±2 teeth around each axis (6 - 2 = 4 and 6 + 2 = 8, etc.): 4, 8, 16, 20, 28, 32, 40, 44, 52, 56, 64, 68, 76, 80, 88, 92 (16 facets).

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() xx8 is 100% equivalent to P2 0 @ 43.0 : gp() x8 m 3 (and P2 6 @ 43.0 : gp() x8 m 3), cutting 0 ± 3 = 93, 3 repeated 8 times: 3, 9, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, 81, 87, 93.
  • P2 4 @ 42.2 : mp(P1) xx8 is 100% equivalent to P2 0 @ 42.2 : mp(P1) x8 m 4 (or P2 6 @ 42.2 : mp(P1) x8 m 2), cutting 0 ± 4 repeated 8 times: 4, 8, 16, 20, 28, 32, 40, 44, 52, 56, 64, 68, 76, 80, 88, 92.

[!IMPORTANT] Don't Confuse 3 @ ... xx8 with 3 @ ... x8 m 3! Remember that the number after m is the ± delta index relative to IDX, not an absolute tooth index:

  • P2 3 @ 43.0 : gp() xx8 (= P2 0 @ 43.0 : gp() x8 m 3) mirrors across 0 (0 ± 3), cutting 3, 9, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, 81, 87, 93.
  • P2 3 @ 43.0 : gp() x8 m 3 places the mirror center at 3 and applies a ±3 delta (3 - 3 = 0 and 3 + 3 = 6), cutting 0, 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() (or TierAP("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.