Chapter 15: Inspecting the Virtual Stone — The stone() API
What if your script wants to ask a question about the stone it has cut so far—such as:
- "What is the current Table Percentage (
tablePercentage), Total Depth Percentage (depthPercentage), or Length-to-Width Ratio (lengthWidthRatio)?" - "Is the girdle continuous and level around the stone (
isGirdleEven,isGirdleOK)?" - "How many surviving facets (
facetCount) and vertices (vertexCount) are on the stone right now?"
Calling stone() anywhere in an FSL or Lua script captures a live reflection snapshot of the 3D gemstone polyhedron at that exact step in the cutting sequence!
1. Stone-Level Properties Returned by stone()
When you write s = stone() (FSL) or local s = stone() (Lua), the returned object exposes the following overall metrics and arrays:
| Property | Type | Description |
|---|---|---|
s.name | String | Current gemstone title. |
s.refractiveIndex | Number | Active refractive index (ri). |
s.facetCount | Number | Total number of surviving polygon faces on the 3D polyhedron. |
s.vertexCount | Number | Total number of unique 3D vertices on the polyhedron. |
s.tablePercentage | Number | Width of the flat 0° Table (T) expressed as a percentage of stone width (0–100). |
s.depthPercentage | Number | Total stone height divided by stone width (height / width * 100). |
s.crownHeight | Number | Vertical height of the Crown above the girdle plane (as % of width). |
s.pavilionDepth | Number | Vertical depth of the Pavilion below the girdle plane (as % of width). |
s.girdleThickness | Number | Average vertical thickness of the 90° Girdle band (as % of width). |
s.lengthWidthRatio | Number | Ratio of longest horizontal caliper dimension to narrowest (1.0 for rounds/squares). |
s.compactness | Number | Volumetric efficiency ratio comparing the polyhedron volume to its bounding box. |
s.isGirdleEven | Boolean | true if all girdle segments have consistent vertical height around the stone. |
s.isGirdleOK | Boolean | true if the girdle forms a valid, closed perimeter without zero-thickness overcuts. |
s.vertices | Array<Point> | List of all unique 3D vertices (Point(x, y, z)) on the polyhedron. |
s.faces | Array<Face> | List of every surviving 3D polygon face on the polyhedron (see below). |
2. Inspecting Individual Faces (s.faces)
Each entry f in s.faces represents a single surviving polygon face on the 3D stone:
| Face Property | Type | Description |
|---|---|---|
f.tier | String | Tier name that created this facet (e.g., "P1", "C2", "T"). |
f.index | Number | Gear tooth index of this specific facet (e.g., 0, 12, 24). |
f.angle | Number | Mast tilt angle (0°–90°) of the facet. |
f.area | Number | 3D surface area of the polygon. |
f.centroid | Point | 3D center of mass (Point(x, y, z)) of the facet polygon. |
f.normal | Vector | Outward-pointing unit normal vector (Vector(x, y, z)). |
f.vertices | Array<Point> | Ordered loop of 3D Point vertices around the facet perimeter. |
f.isPavilion / f.isCrown / f.isGirdle | Boolean | Region classification flags for filtering faces by hemisphere. |
3. Interactive Example: Querying Metrics & Enforcing Optimization Constraints
One of the most powerful uses of stone() is combining it with assert() to keep the GPU Performance Optimizer within practical gem-cutting boundaries—for example, ensuring the Table Percentage stays between 45% and 68%, total depth stays below 75%, and the girdle remains valid (s.isGirdleOK)!
Click Run (Ctrl+Enter / Cmd+Enter) in the playground below and look at the Script Output panel to see the live stone() report:
name = "Stone() Reflection & Constraint Demo"
ri = 1.76
gear = 96
color = "#38bdf8"
P1 3 @ 43.00 +/- 1.0 : cp() xx8
G1 3 @ 90.00 : size xx8
P2 0 @ 41.50 +/- 1.5 : gp() x8
C1 3 @ 42.00 +/- 2.0 : mp(P1, P2) + girdle xx8
C2 0 @ 34.50 +/- 1.5 : gp() x8
C3 6 @ 22.00 +/- 1.5 : mp(C1) x8
T 0 @ 0.00 : mp(C2) x1
// Capture live 3D stone snapshot
s = stone()
print("Gem Name:", s.name, "| RI:", s.refractiveIndex)
print("Total Facets:", s.facetCount, "| Vertices:", s.vertexCount)
print("Table %:", Math.round(s.tablePercentage * 10) / 10, "| Depth %:", Math.round(s.depthPercentage * 10) / 10)
print("Girdle OK:", s.isGirdleOK)
// Guardrails enforced during GPU Optimization:
assert(s.isGirdleOK, "Girdle must remain continuous and valid")
assert(s.tablePercentage >= 45.0, "Table became too small (< 45%)")
assert(s.tablePercentage <= 68.0, "Table became too wide (> 68%)")
assert(s.depthPercentage <= 75.0, "Stone became too deep (> 75%)")
-- lua script
name("Stone() Reflection & Constraint Demo")
ri(1.76)
gear(96)
color("#38bdf8")
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")
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")
-- Capture live 3D stone snapshot
local s = stone()
print("Gem Name:", s.name, "| RI:", s.refractiveIndex)
print("Total Facets:", s.facetCount, "| Vertices:", s.vertexCount)
print("Table %:", math.floor(s.tablePercentage * 10 + 0.5) / 10, "| Depth %:", math.floor(s.depthPercentage * 10 + 0.5) / 10)
print("Girdle OK:", s.isGirdleOK)
-- Guardrails enforced during GPU Optimization:
assert(s.isGirdleOK, "Girdle must remain continuous and valid")
assert(s.tablePercentage >= 45.0, "Table became too small (< 45%)")
assert(s.tablePercentage <= 68.0, "Table became too wide (> 68%)")
assert(s.depthPercentage <= 75.0, "Stone became too deep (> 75%)")
Next, let’s dive into the final chapter of Part II—Chapter 16: Complete Lua Scripting Guide — Loops, Tables & Procedural Cuts—to see how Lua unlocks full algorithmic gemstone design.