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 16: Complete Lua Scripting Guide — Loops, Tables & Procedural Cuts

PART II · CHAPTER 16 TierAD / TierAP / TierPP · Optimizable val() · Procedural Loops & Tables · Spiral & Cone Generators

Throughout Part II, you have seen how FSL and Lua sit side by side atop ProFacet’s 3D geometry kernel. While FSL shines for declarative, diagram-style cuts and functional pipelines, Lua (-- lua script) gives you a full imperative programming language with for and while loops, mutable tables, and modular helper functions.

This chapter is your complete reference and cookbook for scripting gemstones in Lua.


1. Activating Lua Mode & Global Settings

Start any script with -- lua script on line 1. ProFacet’s Lua environment exposes global configuration functions that mirror FSL’s top-of-file metadata (calling gear() or size() with no arguments returns the current setting):

-- lua script
name("Procedural Sapphire")
ri(1.76)
gear(96)
cw(true)
color("#38bdf8")
absorption(1.2)
notes("Generated algorithmically in Lua")
tags("lua, procedural, sapphire")

-- Built-in girdle offset vector (3% of radius along +Z) is pre-defined as `girdle`,
-- or you can customize it:
girdle = Vector(0, 0, 0.03)

2. Cutting Facet Tiers: TierAD, TierAP, TierPP & val()

In Lua, you cut facet tiers using three dedicated functions corresponding to ProFacet’s three design styles:

A. The Three Tier Constructors

  1. TierAD(name, index, angle, depth, [sym], [opts]) — Angle + Numeric Depth (Style 1):
    -- Cut 16 vertical girdle facets at distance 1.0 from center:
    TierAD("G1", 0, 90.0, 1.0, "x16")
    
  2. TierAP(name, index, angle, point, [sym], [opts]) — Angle + Landmark Point (Style 2):
    -- Cut 8 pavilion mains at 41.5° to the centerpoint cp():
    TierAP("P1", 0, 41.5, cp(), "x8")
    
    -- Cut 16 mirrored crown breaks at 42.0° to the top of the girdle (0 ± 3):
    TierAP("C1", 0, 42.0, gp():add(girdle), "x8 m 3")
    
  3. TierPP(name, index, point1, point2, [sym], [opts]) — Point + Point (Style 3, Angle Computed Automatically):
    -- Slice a plane at tooth 12 passing through cp() and 85% down the PF1:0 / G1:0 edge:
    TierPP("PF2", 12, cp(), ep(edge("PF1:0", "G1:0"), 0.85), "x4")
    

B. Symmetry Strings & Optional Options Table (opts)

ArgumentExamplesMeaning
index0, 3, or {6, 30, 54}Single gear tooth or a Lua table of explicit gear teeth.
sym"x8", "x8 m 3", "xx8", "x1"Rotational symmetry (xN), mirror delta ±M around axis index (xN m M), or zero-axis mirror of cut tooth index (xxN). If omitted, inherits the previous tier's symmetry.
opts{frosted = true, color = "#f43f5e", side = "up", primary_cut_index = 6}Optional table of per-tier overrides (matte finish, custom RGB color, explicit hemisphere "up"/"down", or primary reference tooth).

C. Optimizable Parameters in Lua (val(...))

To mark any angle, depth, or variable for the GPU Performance Optimizer (matching +/- in FSL), wrap the number in val(...):

  • val(41.5, 1.5) — Equivalent to 41.5 +/- 1.5 in FSL (explores [40.0, 43.0]).
  • val(42.0, "2%") — Equivalent to 42.0 +/- 2% in FSL.
  • val(41.5, 40.0, 43.0) — Explicit (initial, min, max) bounds.

3. Point Helpers & 3D Vector Methods in Lua

In Lua, tier and facet names passed to mp() and edge() are strings ("P1", "C1:0", "!G1"), and 3D Point / Vector arithmetic uses explicit methods:

Helper / TypeLua SyntaxNotes
Center & Girdle Pointscp(), gp()Identical to FSL.
Meetpointsmp("P1", "G1", "!PF1")Pass tier names, "Tier:Index" strings, or "!Exclude" strings.
Edges & Interpolationedge("C1:0", "C1:6")
ep(edge("C1:0", "C1:6"), 0.5)
ep(p1, p2, t) also interpolates between any two Point objects.
Projections & Gridsprz(pt) / prz(pt, "C1:0")
fred(p1, p2, edge("P1:0", "P1:12"))
grid(cols, rows, x, y)
surface(index, frac)
Full parity with FSL. Use resolve(pt) if you need to inspect .x, .y, .z on a lazy point helper before passing it to a tier.
3D Point & VectorPoint(x, y, z)
Vector(x, y, z)
Methods: p:add(v), p:sub(v), p1:distance(p2), v:mul(s), v:div(s), v:unm(), v:length(), v:normalize(), v:dot(v2), v:cross(v2).
CAM PreformsRound(43, 16), Oval(43, 1.35, 5), RectTr(1.4, 43, 0.28, 0)…All built-in CAM functions are available as global Lua functions.

4. Cookbook Recipe 1: Parametric N-Tier Portuguese Cut Generator

In a classic Portuguese cut, multiple tiers of rhomboid facets step down from the girdle to the culet. Below, compare how FSL (Math.range) and Lua (for k = 2, pavTiers do) generate an interlocking 4-tier Portuguese Pavilion cone and Crown wheel:

name  = "Procedural N-Tier Portuguese Cut"
ri    = 1.76
gear  = 96
cube  = 3
color = "#ec4899"

G1 0 @ 90.0 : size x16

// 1. Base Pavilion cone & girdle break (x16)
P1 0 @ 62.0 : cp() x16
P2 3 @ 57.0 : gp() x16

// Each interlocking Pavilion tier Pk meets mp(P(k - 2))!
Math.range(3, 6).forEach(k => {
  idx  = ((k - 1) % 2) * 3
  ang  = 62.0 - (k - 1) * 5.0
  prev = concat(P, k - 2)
  concat(P, k) idx @ ang : mp(prev) x16
})

// 2. Base Crown tiers + interlocking Crown wheel C3..C5
C1 0 @ 46.0 : mp(P1) + girdle x16
C2 3 @ 41.0 : gp() x16

Math.range(3, 6).forEach(k => {
  idx  = ((k - 1) % 2) * 3
  ang  = 46.0 - (k - 1) * 5.0
  prev = concat(C, k - 2)
  concat(C, k) idx @ ang : mp(prev) x16
})

T 0 @ 0.0 : mp(C4) x1
-- lua script
name("Procedural N-Tier Portuguese Cut")
ri(1.76)
gear(96)
cube(3)
color("#ec4899")

TierAD("G1", 0, 90.0, 1.0, "x16")

-- 1. Base Pavilion cone & girdle break (x16)
TierAP("P1", 0, 62.0, cp(), "x16")
TierAP("P2", 3, 57.0, gp(), "x16")

-- Each interlocking Pavilion tier Pk meets mp(P(k - 2))!
for k = 3, 5 do
  local idx  = ((k - 1) % 2) * 3
  local ang  = 62.0 - (k - 1) * 5.0
  local prev = "P" .. (k - 2)
  TierAP("P" .. k, idx, ang, mp(prev), "x16")
end

-- 2. Base Crown tiers + interlocking Crown wheel C3..C5
TierAP("C1", 0, 46.0, mp("P1"):add(girdle), "x16")
TierAP("C2", 3, 41.0, gp(), "x16")

for k = 3, 5 do
  local idx  = ((k - 1) % 2) * 3
  local ang  = 46.0 - (k - 1) * 5.0
  local prev = "C" .. (k - 2)
  TierAP("C" .. k, idx, ang, mp(prev), "x16")
end

TierAP("T", 0, 0.0, mp("C4"), "x1")

5. Cookbook Recipe 2: Algorithmic Vortex / Spiral Turbine Crown

By computing individual tooth indices inside a loop, you can create chiral (spiral/vortex) cuts where each successive tier rotates by +2 gear teeth clockwise relative to the tier below it:

name  = "Spiral Vortex Turbine"
ri    = 2.15
gear  = 96
color = "#38bdf8"

// High-brilliance 16-facet pavilion & girdle
P1 3 @ 43.0 : cp() xx8
G1 3 @ 90.0 : size xx8
P2 0 @ 41.5 : gp() x8

// Spiral Crown: each tier rotates +2 teeth clockwise and steps shallower!
C1 3 @ 43.0 : mp(P1, P2) + girdle xx8

spiralSteps = 3
Math.range(1, spiralSteps + 1).forEach(step => {
  tooth = (step * 2) % 96
  angle = 36.0 - step * 6.0
  frac  = 1.0 - step * 0.14
  concat(C, step + 1) tooth @ angle : surface(frac, 0.5) x8
})

T 0 @ 0.0 : surface(0.46, 0.5) x1
-- lua script
name("Spiral Vortex Turbine")
ri(2.15)
gear(96)
color("#38bdf8")

-- High-brilliance 16-facet pavilion & girdle
TierAP("P1", 3, 43.0, cp(), "xx8")
TierAD("G1", 3, 90.0, size, "xx8")
TierAP("P2", 0, 41.5, gp(), "x8")

-- Spiral Crown: each tier rotates +2 teeth clockwise and steps shallower!
TierAP("C1", 3, 43.0, mp("P1", "P2"):add(girdle), "xx8")

local spiralSteps = 3
for step = 1, spiralSteps do
  local tooth = (step * 2) % 96
  local angle = 36.0 - step * 6.0
  local frac  = 1.0 - step * 0.14
  TierAP("C" .. (step + 1), tooth, angle, surface(frac, 0.5), "x8")
end

TierAP("T", 0, 0.0, surface(0.46, 0.5), "x1")

End of Part II — Explore the Showcase & Reference Appendices!

You now have complete command of both Part I (The Visual Studio & Optical Workbench) and Part II (FSL & Lua Parametric Scripting).

In the Appendices that follow, you can explore: