Statements
Every line in an .fsl file starts with a keyword or tier name. This chapter explains what each statement does, why you would reach for it, and where it appears in the example at the end.
set – project-wide settings
Use set to update metadata (set name, set ri) or machine configuration (set gear, set girdle). The change applies immediately and carries forward to later lines.
| Command | Value syntax | What it controls | Notes |
|---|---|---|---|
set name "Brilliant Oval" | Quoted string | Updates the project title used in the viewer, analyzer panels, and printable exports. | Keep the quotes when you need spaces; later set name calls overwrite the previous label. |
set ri 1.760 | Plain number or optimizable literal (for example [1.76, 1.70, 1.80]) | Defines the refractive index the renderer, analyzer, and optimizer use for light calculations. | Makes RI available to the optimizer if you supply the square-bracket form. |
set color #ffd166 | Hex literal (#fff, #ffaa33), named color (red, cyan, ...). | Sets the simulated material color in screenshots and raytraces. | |
set absorption 0.6 | Number from 0.0–1.0 | Controls how strongly the gem colour tints the interactive WebGL preview. | Defaults to 0.6; lower numbers reduce tinting while 1.0 fully uses the gem colour. |
set gear 96 cw | Positive integer followed by optional cw or ccw | Sets the index gear tooth count and dop rotation direction for every later facet. | Gear must be an integer; include cw/ccw only when you need to flip the rotation. |
set girdle 4.5 | Number representing a percentage of the stone’s average width | Adjusts how thick the girdle is when interpreting +/- girdle offsets. | Typical values are 2–5; larger numbers make the girdle offsets push farther. |
set cube 3.0 | Number interpreted as the cube’s edge length | Rebuilds the starting blank as a cube of the given size before additional cuts. | This discards previously cut geometry, so place it near the top of a file. |
let – save a value for later
let table = mp(G1) stores a point or number so you can reuse it further down. Inside macros, the binding disappears when the macro finishes; elsewhere it lives to the end of the file. Edge helpers are the only exception: they emit two points, so let edge_ref = edge(...) is invalid—always destructure the pair.
Need both endpoints of an existing facet edge? Add a second identifier on the left and feed an edge(...) helper. The interpreter assigns the ordered pair of edge points to those identifiers. Replace whichever side you do not care about with _ to discard it. In a fresh file you can try:
set name "Edge destructuring"
set gear 96
P1 down 0 @ 41.8 : 0.18 x8
let break_a, break_b = edge(P1:0, P1:12)
let keep, _ = edge(P1:12, P1:24)
Those bindings behave like any other point variable—you can aim facets at them, drop debug markers, or pass them into macros.
show – drop a marker (or edge) in the viewer
show mp(P1) drops a marker using the default highlight colour (#ffd166). Add up or down (right after show) if you want to force the side, and optionally supply a colour: either one of the named options (cyan, orange, etc.) or a hex literal such as #ffe422 or #fff. The web studio keeps a small picker next to the editor so you can drop in hex values without memorising them.
Need to highlight a segment instead of a single point? Feed show edge(Tier:Index, Tier:Index) and the viewer/printable exports draw the coloured line. Just like the let statement, show does not accept edge variables directly—call edge(...) inline or reuse the destructured point pair.
Macros – reuse a favourite sequence
define macro wraps statements so you can replay them with a single command. Every parameter is named ($Macro(tier = "C1")), and defaults live either in the header or inline using ${param = ...}.
They are an advanced feature, often used for complex gem outlines.
Facet commands – the main event
When a line starts with a tier name (P1, Star, etc.) you are cutting a facet. Read it like a simple recipe:
Tier [up|down] index @ angle : target xN ["note"] frosted
Go left to right:
- Tier – the label that will appear in the printable diagram.
- up / down – crown or pavilion. Leave it off when the tier already implies the side (for example, a
Ctier lives on the crown, aPtier is pavilion). - index @ angle – which tooth on the gear and which angle to lock in. Legacy notes that show
<still parse the same way. - : target – how far to swing the quill. This can be a depth (
: 0.18), a meet point (: mp(G1)), or the special wordsizefor auto-depth on 90° girdle cuts. - xN – how many times to echo the facet around the dop. Use
xxNwhen you want mirror-image pairs (for example, left/right star facets). - "note" / frosted – optional add-ons: custom printable text or hatch marks.
Here is the classic pavilion break written that way:
P1 down 0 @ 41.8 : 0.18 x8
P1— name in the legend.down— pavilion side.0 @ 41.8— tooth 0, 41.8° on the dial.: 0.18— stop when the quill drops 0.18 units.x8— repeat eight times (every 45°).
Once you remember the pattern, you only need to choose which target style fits:
- Angle + depth —
P1 down 0 @ 41.8 : 0.18 x8. Great for pavilion mains, breaks, or any cut where you know the depth. Use: sizeonly with 90° girdle passes that should land exactly on the girdle thickness. - Angle + point —
C1 up 0 @ 32 : mp(G1) + girdle x16. Aim the facet at a meet point or helper. Add+ girdle/- girdleif the point should sit slightly outside or inside the default girdle radius. - Point pair —
G3 0 : mp(G1) : mp(C2) x16. Define the plane using two points instead of an angle. Ideal for tidying a girdle or bridging between meet points when the trig would be a pain.
Tier naming, sides, and base index rules
Every tier label must be a single string with no whitespace inside it, and it has to start with an alphanumeric character. Reserved keywords (set, let, show, etc.) are off limits as tier names. The optional up/down flag tells the interpreter which side of the stone to use, but most of the time the engine can infer it:
- Names that start with
Pdefault to the pavilion. - Names that start with
Cdefault to the crown. - If you omit the side and the previous cut specified one, that side carries forward.
That’s why a table named T typically doesn’t need up—it inherits the current crown context. You can always override the inference by writing the side explicitly.
The base_index argument is zero-based and must stay below gear / symmetry. Until you dig into the Symmetry section later in this guide, use this mental model:
- With a 96 index gear and 4-fold symmetry, the valid base index range is
0 .. (96 / 4 - 1)→0 .. 23.
Some quick examples:
P1 1 … // Pavilion cut using base index 1
G2 1 … // Girdle tier; inherits the pavilion side from P1
C1 3 … // Crown cut using base index 3
X8 down … // Non-standard tier name forced onto the pavilion
Everything together
Paste the snippet below into a fresh file to see each statement in context. Feel free to tweak the numbers and watch how the studio responds.
set name "Statement Tour"
set gear 96
set ri 1.760
P1 down 0 @ 41.8 : 0.18 x8
P2 down 6 @ 39.4 : mp(P1) x8
let break_angle = 23.2
show mp(P1) #0011ff
G1 0 @ 90 : size x16
G2 0 @ 90 : mp(G1) x16
let table = mp(G1)
show table #ff004c
define macro CrownRing(tier, angle = 32.0, target = table)
${tier} up 0 @ ${angle} : ${target} + girdle x16
end macro
$CrownRing(tier = "C1", angle = break_angle)
$CrownRing(tier = "C2", angle = 27.5)
Once you are comfortable with the building blocks, jump to Expressions to see how to shape angles, numbers, and points inside those statements.
Curious how we handle your designs or what to expect from the simulator? Read the Privacy, ownership, and disclaimer note for the plain-language policy.