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 9: The Dual Language Engine — FSL & Lua Side by Side

PART II · CHAPTER 9 Declarative FSL vs. Imperative Lua · Auto-Detection · The Complete Rosetta Stone

Welcome to Part II: FSL & Lua — Parametric & Algorithmic Gem Design.

In Part I, you saw how every action in the Interactive Slicer builds a gemstone visually. Under the hood, ProFacet’s 3D geometry kernel is driven by a dual-language scripting engine that natively executes both FSL (Faceting Specification Language) and Lua.

Why does ProFacet offer two languages instead of one?

  1. FSL (Faceting Specification Language) is designed to look and read like a traditional gem-cutting diagram. Each line (P1 0 @ 41.5 : cp() x8) states a single tier's index, mast angle, meetpoint target, and symmetry fold in fewer characters than any general-purpose language—while still giving you variables, 3D vectors, functional array pipelines (map, filter, reduce), and +/- GPU optimization hints.
  2. Lua (-- lua script) is a full, industry-standard imperative programming language with for and while loops, mutable tables, if/elseif/else branching, and standard math.* functions. Whenever you want to write a procedural algorithm—such as a spiral vortex crown, a parametric step-cut generator with variable tier counts, or a mathematical sculpture—Lua gives you unrestricted programming power connected to the exact same 3D cutting engine and Optimizer.

1. How ProFacet Detects FSL vs. Lua

You can write either language right inside the Spec Editor (</> Spec Editor). ProFacet automatically detects which language your script is written in:

  • FSL scripts use C-style comments (// comment) and declarative @ / : tier lines (P1 0 @ 41.5 : cp() x8).
  • Lua scripts start with a Lua comment (-- lua script) and use standard Lua function calls (TierAP("P1", 0, 41.5, cp(), "x8")).

[!TIP] Always Start Lua Scripts with -- lua script Placing -- lua script on line 1 guarantees that both the Spec Editor and the interactive playgrounds in this book immediately activate Lua syntax highlighting and the Lua runtime.


2. Line-by-Line Comparison: The Same Gemstone in FSL & Lua

Click between FSL and Lua in the top bar of the live playground below and click Run (Ctrl+Enter / Cmd+Enter) to see how identically the two languages construct a Sapphire Round Brilliant:

// 1. Stone & Machine Metadata
name  = "Sapphire Round Brilliant"
ri    = 1.76          // Corundum (Sapphire / Ruby)
gear  = 96            // 96-tooth index gear
color = "#38bdf8"

// 2. Pavilion & Girdle Tiers
P1 3 @ 43.00 +/- 1.0 : cp() xx8       // 16 mirrored pavilion breaks meeting cp()
G1 3 @ 90.00         : size xx8       // 16 vertical girdle facets at radius 1.0
P2 0 @ 41.50 +/- 1.5 : gp() x8        // 8 pavilion mains meeting the girdle

// 3. Crown & Table Tiers
C1 3 @ 42.00 +/- 2.0 : mp(P1, P2) + girdle xx8  // 16 crown breaks + girdle thickness
C2 0 @ 34.50 +/- 1.5 : gp() x8                  // 8 crown mains meeting the girdle
C3 6 @ 22.00 +/- 1.5 : mp(C1) x8                // 8 star facets meeting C1
T  0 @ 0.00          : mp(C2) x1                // 1 flat table meeting C2
-- lua script
-- 1. Stone & Machine Metadata
name("Sapphire Round Brilliant")
ri(1.76)
gear(96)
color("#38bdf8")

-- 2. Pavilion & Girdle Tiers
TierAP("P1", 3, val(43.00, 1.0), cp(), "xx8")
TierAD("G1", 3, 90.00,           size, "xx8")
TierAP("P2", 0, val(41.50, 1.5), gp(), "x8")

-- 3. Crown & Table Tiers
TierAP("C1", 3, val(42.00, 2.0), mp("P1", "P2"):add(girdle), "xx8")
TierAP("C2", 0, val(34.50, 1.5), gp(), "x8")
TierAP("C3", 6, val(22.00, 1.5), mp("C1"), "x8")
TierAP("T",  0, 0.00,            mp("C2"), "x1")

3. Anatomy of a Cut Statement in Both Languages

In FSL:

  C1     3     @  42.00 +/- 2.0   :   mp(P1, P2) + girdle   xx8
────── ─────  ────────────────── ─── ───────────────────── ─────
 Tier   Base    Angle (°) + Opt        Meetpoint Target +   Sym
 Name  Index      Search Hint            Girdle Offset     (Mir)

In Lua:

  TierAP( "C1",   3,   val(42.00, 2.0),   mp("P1", "P2"):add(girdle),   "xx8" )
          ─────  ───  ─────────────────   ───────────────────────────   ──────
          Tier   Base  Angle (°) + Opt      Meetpoint Target +          Mirrored
          Name  Index    Search Hint          Girdle Offset             Symmetry

4. The Complete FSL ↔ Lua Rosetta Stone

Keep this side-by-side cheat sheet handy as you read through Part II:

FeatureFSL SyntaxLua Syntax (-- lua script)
Comments// Single-line comment-- Single-line comment
Metadata Settingsname = "Star Ruby"
ri = 1.76
gear = 96
color = "#e11d48"
name("Star Ruby")
ri(1.76)
gear(96)
color("#e11d48")
VariablespavAngle = 41.5
girdle = Vector(0, 0, 0.04)
local pavAngle = 41.5
local girdle = Point(0, 0, 0.04)
Optimizable Numbers41.5 +/- 1.5
42.0 +/- 2%
val(41.5, 1.5)
val(42.0, "2%")
CAM PreformsRound(43, 16)
RectTr(1.4, 43, 0.28, 0)
Round(43, 16)
RectTr(1.4, 43, 0.28, 0)
Style 1: Angle + DepthP1 0 @ 41.8 : 0.25 x8TierAD("P1", 0, 41.8, 0.25, "x8")
Style 2: Angle + PointP1 0 @ 41.5 : cp() x8TierAP("P1", 0, 41.5, cp(), "x8")
Style 3: Point-PairC1 0 : gp() + girdle : mp(C2) x8TierPP("C1", 0, gp():add(girdle), mp("C2"), "x8")
Mirrored SymmetryP2 0 @ 43.0 : gp() x8 m 3
(axis 0 with ±3 delta, or zero-axis shorthand P2 3 @ 43.0 : gp() xx8)
TierAP("P2", 0, 43.0, gp(), "x8 m 3")
(or zero-axis shorthand TierAP("P2", 3, 43.0, gp(), "xx8"))
Explicit Tooth ListP3 [0, 24, 48] @ 42.0 : gp()TierAP("P3", {0, 24, 48}, 42.0, gp())
Frosted / NotesG1 0 @ 90 : size x16 { frosted: true }TierAD("G1", 0, 90, size, "x16", { frosted = true })
Meetpoint Helperscp(), gp(), mp(P1, P2, !G1)cp(), gp(), mp("P1", "P2", "!G1")
Edge Interpolationep(edge(C1:0, C1:6), 0.5)ep(edge("C1:0", "C1:6"), 0.5)
3D PrimitivesPoint(x, y, z), Vector(x, y, z), Plane(...)Point(x, y, z), Vector(x, y, z), Plane(...)
Inspect Stone (stone())s = stone(); print(s.tablePercentage)local s = stone(); print(s.tablePercentage)
Assertionsassert(s.tablePercentage > 45, "Small table")assert(s.tablePercentage > 45, "Small table")
Loops / IterationMath.range(0, 8, 1).forEach((i) => ...)for i = 0, 7 do ... end

5. Why Coding Your Cuts Changes Everything

When a gemstone is defined as a parametric script rather than a static list of vertices:

  1. One-Line Material Adaptation: You can compute the critical angle directly from ri (crit = asin(1.0 / ri)) and express your Pavilion angles relative to crit. Change ri = 1.54 to ri = 2.42 and the entire Pavilion re-angles itself automatically!
  2. Proportion-Locked Scaling: When you stretch an Oval from 1.25× to 1.50×, tiers anchored with gp(), mp(), ep(), or surface(u, v) automatically recompute their exact angles and depths so every meetpoint stays closed.
  3. Instant Multi-Tier Generation: Use a 3-line FSL .forEach() pipeline or a Lua for loop to generate a 10-tier Portuguese pavilion or a 64-facet geodesic dome without repeating yourself.

Next, let’s establish the exact 3D coordinate system, machine configuration settings, and symmetry rules in Chapter 10: Coordinate System, Machine Settings & Symmetry Rules.