diff --git a/src/pages/docs/api/cdl-parser.astro b/src/pages/docs/api/cdl-parser.astro index f1e9fca..84ca504 100644 --- a/src/pages/docs/api/cdl-parser.astro +++ b/src/pages/docs/api/cdl-parser.astro @@ -4,16 +4,56 @@ import { Breadcrumb, CodeBlock, APISignature, PropsTable, PageNav } from '../../ import { Container } from '../../../components/ui-astro'; const crystalDescriptionAttrs = [ - { name: 'system', type: 'CrystalSystem', description: 'Crystal system enum' }, - { name: 'point_group', type: 'str', description: 'Point group symbol' }, - { name: 'forms', type: 'list[Form]', description: 'List of crystal forms' }, - { name: 'twin_law', type: 'str | None', description: 'Optional twin law name' }, - { name: 'modifiers', type: 'dict[str, Any]', description: 'Optional modifiers (elongate, etc.)' }, + { name: 'system', type: 'str', description: 'Crystal system name (e.g., "cubic", "trigonal")' }, + { name: 'point_group', type: 'str', description: 'Hermann-Mauguin point group symbol (e.g., "m3m")' }, + { name: 'forms', type: 'list[FormNode]', description: 'List of form nodes (CrystalForm or FormGroup)' }, + { name: 'modifications', type: 'list[Modification]', description: 'Morphological modifications (elongate, flatten, etc.)' }, + { name: 'twin', type: 'TwinSpec | None', description: 'Optional twin specification' }, + { name: 'phenomenon', type: 'PhenomenonSpec | None', description: 'Optional optical phenomenon' }, + { name: 'definitions', type: 'list[Definition] | None', description: 'Named definitions (@name = expression)' }, + { name: 'doc_comments', type: 'list[str] | None', description: 'Doc comments (#! Key: Value)' }, ]; -const formAttrs = [ - { name: 'miller_indices', type: 'MillerIndex', description: 'Miller indices for this form' }, - { name: 'distance', type: 'float', description: 'Distance from origin (default 1.0)' }, +const crystalFormAttrs = [ + { name: 'miller', type: 'MillerIndex', description: 'Miller index defining the form' }, + { name: 'scale', type: 'float', description: 'Distance scale (default 1.0, larger = more truncated)' }, + { name: 'name', type: 'str | None', description: 'Original name if using named form (e.g., "octahedron")' }, + { name: 'features', type: 'list[Feature] | None', description: 'Per-form feature annotations' }, + { name: 'label', type: 'str | None', description: 'Optional label (e.g., "prism" in prism:{10-10})' }, +]; + +const formGroupAttrs = [ + { name: 'forms', type: 'list[FormNode]', description: 'Child form nodes in this group' }, + { name: 'features', type: 'list[Feature] | None', description: 'Shared features applied to all children' }, + { name: 'label', type: 'str | None', description: 'Optional group label' }, +]; + +const featureAttrs = [ + { name: 'name', type: 'str', description: 'Feature type (phantom, trigon, silk, colour, etc.)' }, + { name: 'values', type: 'list[int | float | str]', description: 'Feature values (numbers, identifiers, color specs)' }, +]; + +const twinSpecAttrs = [ + { name: 'law', type: 'str | None', description: 'Named twin law (spinel, brazil, japan, etc.)' }, + { name: 'axis', type: 'tuple | None', description: 'Custom twin axis [x, y, z]' }, + { name: 'angle', type: 'float', description: 'Rotation angle in degrees (default 180)' }, + { name: 'twin_type', type: 'str', description: 'Type: "contact", "penetration", or "cyclic"' }, + { name: 'count', type: 'int', description: 'Number of twin individuals (default 2)' }, +]; + +const modificationAttrs = [ + { name: 'type', type: 'str', description: 'Type: "elongate", "truncate", "taper", "bevel", or "flatten"' }, + { name: 'params', type: 'dict[str, Any]', description: 'Parameters (e.g., {"axis": "c", "ratio": 1.5})' }, +]; + +const phenomenonSpecAttrs = [ + { name: 'type', type: 'str', description: 'Phenomenon type (asterism, chatoyancy, etc.)' }, + { name: 'params', type: 'dict[str, int | float | str]', description: 'Parameters (e.g., {"value": 6})' }, +]; + +const definitionAttrs = [ + { name: 'name', type: 'str', description: 'Definition name (from @name = expression)' }, + { name: 'body', type: 'list[FormNode]', description: 'Parsed form nodes for the definition body' }, ]; --- @@ -33,19 +73,20 @@ const formAttrs = [
Parse and validate Crystal Description Language (CDL) expressions. - Zero external dependencies. + Zero external dependencies. Version 1.3.0.
-Parse a CDL expression string into a structured CrystalDescription object.
Parse a CDL string into a structured CrystalDescription object.
+ Handles comments, definitions, forms, modifications, twins, and phenomena.
Parameters:
expression - CDL expression stringtext - CDL expression stringReturns: CrystalDescription object
Raises: CDLParseError if the expression is invalid
Raises:
+ParseError - if the expression has a syntax errorValidationError - if semantically invalid (e.g., wrong point group for system)Validate a CDL expression without fully parsing it. Returns detailed error information.
+Validate a CDL expression without raising exceptions. Returns a tuple of
+ (is_valid, error_message).
Tokenize a CDL expression into a list of tokens. Useful for syntax highlighting.
+Strip comments from CDL text. Extracts doc comments (#!),
+ removes block comments (/* ... */) and line comments (#).
CrystalDescriptionRepresents a parsed CDL expression.
+The main output of CDL parsing, containing all information needed + to generate a crystal visualization.
FormCrystalFormRepresents a single crystal form (set of symmetry-equivalent faces) + with an optional distance scale for truncation.
+ +FormGroupA parenthesized group of forms with optional shared features and label.
+ Syntax: (form + form)[shared_features]
FormNodeType alias: FormNode = CrystalForm | FormGroup.
+ Used as the element type for CrystalDescription.forms.
FeatureDescribes growth patterns, surface markings, inclusions, or colour properties + on a crystal form.
+ +TwinSpecDefines how crystal twinning should be applied.
+ +ModificationRepresents a single crystal form (set of Miller indices with distance).
+Represents a morphological transformation applied to the crystal shape.
PhenomenonSpecOptical phenomenon specification (asterism, chatoyancy, etc.).
+ +DefinitionA named definition that allows reuse via @name = expression
+ and $name references.
MillerIndexCrystalSystemCDLErrorBase exception for all CDL-related errors.
-Enum of the seven crystal systems.
+ParseErrorRaised when CDL parsing fails due to a syntax error. Contains position information.
CDLParseErrorValidationErrorRaised when parsing fails. Contains detailed error information.
+Raised when CDL is syntactically valid but semantically incorrect + (e.g., invalid point group for the given crystal system).
CRYSTAL_SYSTEMSSet of the seven crystal system names.
+ +POINT_GROUPSDictionary mapping crystal systems to valid point groups.
+Dictionary mapping crystal system names to their valid point groups.
DEFAULT_POINT_GROUPSDictionary mapping each crystal system to its default (highest symmetry) point group.
+ +NAMED_FORMSDictionary mapping form names to Miller indices (h, k, l).
+ +TWIN_LAWSSet of recognised twin law names.
+ +FEATURE_NAMESSet of recognised feature annotation names (phantom, trigon, silk, colour, etc.).
+ +PHENOMENON_TYPESSet of recognised phenomenon types (asterism, chatoyancy, adularescence, etc.).
+ +MODIFICATION_TYPESSet of recognised modification types: elongate, truncate, taper, bevel, flatten.
+ +For advanced use cases (syntax highlighting, custom processing):
+ +Generate 3D crystal geometry from CDL descriptions using half-space intersection - and crystallographic symmetry operations. + and crystallographic symmetry operations. Version 1.0.5.
-Convert a parsed CDL description into 3D geometry.
+Convert a parsed CDL description into 3D geometry. Uses desc.flat_forms()
+ internally to handle FormGroup nodes.
Returns: CrystalGeometry object with vertices, faces, and normals
Apply point group symmetry operations to generate all equivalent planes.
+Convenience function that parses a CDL string and generates geometry in one call.
Compute the convex polyhedron defined by the intersection of half-spaces.
+Compute the convex polyhedron defined by half-space intersection. + Returns vertices and faces.
+ +Apply a twin law to create twinned crystal geometry.
+Get the 3x3 rotation/reflection matrices for a crystallographic point group.
Supported twin laws:
-spinel_law - Cubic {'{111}'} contact twindauphine - Quartz 180° rotation about c-axisbrazil - Quartz reflection twinjapan_law - Quartz {'{11-22}'} contact twincarlsbad - Feldspar twinGenerate all symmetry-equivalent face normals from a single Miller index.
-CrystalGeometryContainer for 3D crystal geometry data.
+Convert Miller indices to a Cartesian normal vector using lattice parameters.
-Get default lattice parameters for a crystal system.
+ +Apply morphological modifications (elongate, flatten, taper) to vertices.
FaceRepresents a single crystal face.
+PlaneRepresents a half-space boundary plane.
+Get the 3x3 rotation/reflection matrices for a point group.
+CrystalGeometry
-matrices = get_symmetry_matrices("m3m")
-print(len(matrices)) # 48 operations
+ Container for 3D crystal geometry data.
-matrices = get_symmetry_matrices("-3m") -print(len(matrices)) # 12 operations`} +LatticeParamsCreate a unit cell with specified parameters.
+Render crystal geometry to SVG for visualization, STL for 3D printing, - and glTF for web/AR/VR applications. + and glTF for web/AR/VR applications. Version 1.0.1.
-Render crystal geometry to SVG format.
+Generate an SVG visualization directly from a CDL string. This is the primary + rendering function - it parses the CDL, generates geometry, and renders to SVG + in one call.
Convenience function to render directly from a CDL string.
+Generate an SVG from raw geometry data (vertices and faces). Use this when you + already have computed geometry and want control over face/edge colours.
Export crystal geometry to STL format for 3D printing.
+Export crystal geometry to STL format for 3D printing. Takes raw vertices + and faces, not a geometry object.
Convert geometry to STL format in memory, returning the file content as bytes.
+Export crystal geometry to glTF 2.0 format for web, AR, and VR applications.
+Export crystal geometry to glTF 2.0 format for web, AR, and VR applications.
+ Stores original polygon edges in extras.crystalEdges for accurate
+ edge rendering.
Convert geometry to glTF format in memory, returning the glTF JSON structure.
-Export to GEMCAD .asc format for gem cutting design.
+Convert an SVG file to raster format (PNG, JPG, or BMP). Requires the
+ raster optional dependencies.
Render multiple crystals efficiently.
+Generate a crystal visualization in any supported format. Wraps a generator + function, automatically converting through SVG for raster outputs.
-Render a properties info panel on a matplotlib axes.
Create a camera for consistent view angles.
+Create an FGA-style info panel dictionary from a mineral preset.
-Low-level drawing functions for building custom visualizations:
-# Use same camera for multiple renders -generate_svg(geom1, "crystal1.svg", camera=camera) -generate_svg(geom2, "crystal2.svg", camera=camera)`} +Project 3D geometry to 2D for custom rendering.
+Functions for 3D-to-2D projection and visibility calculations:
- SQLite database of 94+ mineral presets with CDL definitions, crystal system data, - and gemmological properties. + SQLite database of 96 mineral families (68 natural + 15 synthetic + 9 simulant + 4 composite) + with 128 CDL expressions, crystal system data, and gemmological properties. Version 1.8.1.
-Get a mineral preset by name (case-insensitive).
+Get a mineral preset by name (case-insensitive). Returns a dictionary.
Parameters:
-name - Mineral name (case-insensitive)Get a Mineral object by name. Returns a typed dataclass instead of a dict.
Returns: MineralPreset or None if not found
List all available preset names.
+List all available preset names, optionally filtered by crystal system or category.
Search presets by name, formula, or properties.
+Search presets using full-text search across name, chemistry, and description.
Filter minerals by various criteria.
+ +Get all presets for a specific crystal system.
+Find minerals matching a measured refractive index, sorted by closest match.
Find minerals matching a specific gravity value, sorted by closest match.
+ +Get presets within a hardness range.
+List all synthetic mineral family IDs, optionally filtered by growth method.
Find minerals matching a measured refractive index.
+List all simulant mineral family IDs, optionally filtered by what they imitate.
MineralPresetGet all synthetic and simulant counterparts for a natural mineral.
-Complete mineral data including CDL and gemmological properties.
+List all mineral family IDs filtered by origin type.
+ +Get a MineralFamily object by ID, including synthetic-specific fields.
Get database metadata.
+Classify a gemmological value based on standard thresholds.
Get cut shape factors for carat weight estimation.
-Load a custom SQLite database with additional presets:
+Get minerals with heat treatment temperature data.
+ +Override the default database path for all queries.
MineralDataclass representing a mineral preset with all gemmological properties.
-# Use same API -preset = db.get_preset("custom_mineral") -all_presets = db.list_presets()`} +MineralFamilyThe database includes 94 mineral presets organized by crystal system:
+Dataclass representing a mineral family (normalized structure). Includes
+ synthetic-specific fields like growth_method, manufacturer,
+ and diagnostic_synthetic_features.
Diamond, Spinel, Garnet group, Pyrite, Fluorite...
-Beryl varieties, Apatite, Zincite...
-The database includes 96 mineral families with 128 CDL expressions:
+ +Quartz varieties, Corundum, Tourmaline, Calcite...
+Diamond, Ruby, Emerald, Quartz, Garnet...
Zircon, Rutile, Cassiterite, Vesuvianite...
+CVD Diamond, Flux Ruby, Hydrothermal Emerald...
Topaz, Peridot, Chrysoberyl, Tanzanite...
+CZ, Moissanite, YAG, Glass...
Orthoclase, Jadeite, Spodumene, Malachite...
+Garnet-Topped Doublet, Opal Triplet...
{section.description}
}
+
{item.cdl}
@@ -112,13 +181,31 @@ const examples = [
+cubic[m3m]:{111}@1.5 + {100}@0.8 # More cube
+
+# Add features to specific forms
+cubic[m3m]:{111}@1.0[trigon:dense] + {100}@1.3
+
+# Apply a modification
+trigonal[32]:{10-10}@0.5 + {10-11}@1.2 | elongate(c:2.0)
+
+# Add a twin law
+cubic[m3m]:{111}@1.0 | twin(spinel_law)
+
+# Annotate a phenomenon
+trigonal[-3m]:{10-11}@1.0[silk:dense] | phenomenon[asterism:6]
+
+# Full example with comments, definitions, features, and twin
+#! Mineral: Diamond
+#! Habit: Macle twin
+@oct = {111}@1.0[trigon:sparse]
+cubic[m3m]:$oct + {100}@0.3 | twin(spinel_law)`} />
Try These Examples
diff --git a/src/pages/docs/cdl.astro b/src/pages/docs/cdl.astro
index 97119bf..db2f1e1 100644
--- a/src/pages/docs/cdl.astro
+++ b/src/pages/docs/cdl.astro
@@ -20,15 +20,27 @@ import { Container, Button, Card } from '../../components/ui-astro';
CDL is a domain-specific language for describing crystal morphology using crystallographic
- notation. It combines crystal systems, point groups, and Miller indices to precisely
- define crystal forms.
+ notation. It combines crystal systems, point groups, Miller indices, and optional modifiers
+ to precisely define crystal forms for 3D visualization.
- Syntax Overview
+
+ Current version
+ CDL v1.3
+
+ Includes comments (v1.1), features and phenomena (v1.2), grouping, labels, and definitions (v1.3).
+
+
+
+
+
+
- A CDL expression follows this general format:
+ Basic Syntax
-
+ A CDL expression follows this general structure:
+
+
Components
@@ -36,6 +48,7 @@ import { Container, Button, Card } from '../../components/ui-astro';
Component
+ Required
Description
Example
@@ -43,166 +56,710 @@ import { Container, Button, Card } from '../../components/ui-astro';
system
+ Yes
Crystal system
- cubic, hexagonal, trigonal
+ cubic, trigonal
[point_group]
- Point group symmetry
- [m3m], [6/mmm], [-3m]
+ No
+ Point group symmetry (defaults per system)
+ [m3m], [-3m]
+
+
+ :
+ Yes
+ Separator between header and forms
+
{'{'}hkl{'}'}
- Miller indices
+ Yes
+ Miller index defining a crystal form
{'{'}111{'}'}, {'{'}10-10{'}'}
- @distance
- Distance from origin
+ @scale
+ No
+ Distance from origin (default 1.0)
@1.0, @0.8
+
+ +
+ No
+ Combine multiple forms
+
+
- Crystal Systems
+
+ When the point group is omitted, the default for the system is used (e.g., cubic defaults to m3m).
+
- CDL supports all seven crystal systems:
+
-
- {['cubic', 'hexagonal', 'trigonal', 'tetragonal', 'orthorhombic', 'monoclinic', 'triclinic'].map((system) => (
-
- {system}
-
- ))}
-
+
+
+
+
+
+ The @scale value controls how far each form sits from the crystal centre.
+ Larger values push the form outward, reducing its face area relative to other forms.
+ Smaller values bring it closer, making faces more prominent.
+
- Point Groups
+
+
+
- Point groups define the symmetry operations applied to Miller indices. Each crystal system has specific valid point groups:
+ Crystal Systems and Point Groups
+
+ CDL supports all seven crystal systems and all 32 crystallographic point groups:
System
+ Default
Point Groups
- Cubic
- m3m, 432, -43m, m3, 23
+ cubic
+ m3m
+ m3m, 432, -43m, m-3, 23
- Hexagonal
- 6/mmm, 622, 6mm, -62m, 6/m, 6, -6
+ hexagonal
+ 6/mmm
+ 6/mmm, 622, 6mm, -6m2, 6/m, 6, -6
- Trigonal
+ trigonal
+ -3m
-3m, 32, 3m, -3, 3
- Tetragonal
+ tetragonal
+ 4/mmm
4/mmm, 422, 4mm, -42m, 4/m, 4, -4
- Orthorhombic
+ orthorhombic
+ mmm
mmm, 222, mm2
- Monoclinic
+ monoclinic
+ 2/m
2/m, 2, m
- Triclinic
+ triclinic
+ -1
-1, 1
- Miller Indices
+
+
+
+
+ Miller Indices
+
+ Miller indices define crystal face orientations using curly braces. CDL supports several notations:
+
+
+
+
+ Format
+ Example
+ Description
+
+
+
+
+ Condensed 3-index
+ {'{'}111{'}'}
+ Single-digit indices concatenated
+
+
+ Separated 3-index
+ {'{'}1 1 1{'}'}
+ Space-separated (for multi-digit indices)
+
+
+ 4-index (Miller-Bravais)
+ {'{'}10-10{'}'}
+ For hexagonal and trigonal systems
+
+
+ Negative indices
+ {'{'}10-11{'}'}
+ Minus sign before the digit
+
+
+
- Miller indices define crystal planes. Use curly braces with comma-separated values:
+
+ In 4-index Miller-Bravais notation {'{'}hkil{'}'}, the third index i is
+ redundant (i = -(h+k)) but included for clarity in hexagonal and trigonal systems.
+
-
- - Three indices:
{'{'}h,k,l{'}'} for most systems
- - Four indices:
{'{'}h,k,i,l{'}'} for hexagonal/trigonal (Miller-Bravais)
- - Negative values: Use minus sign, e.g.,
{'{'}10-10{'}'}
-
+ Named Forms
- Common Forms
+ Common crystal forms can be referenced by name instead of Miller indices:
- Indices
- Form Name
+ Name
+ Miller Index
System
- {'{'}111{'}'}
- Octahedron
+ cube
+ {'{'}100{'}'}
Cubic
- {'{'}100{'}'}
- Cube
+ octahedron
+ {'{'}111{'}'}
Cubic
+ dodecahedron
{'{'}110{'}'}
- Rhombic dodecahedron
Cubic
- {'{'}10-10{'}'}
- Hexagonal prism
+ trapezohedron
+ {'{'}211{'}'}
+ Cubic
+
+
+ prism
+ {'{'}100{'}'}
+ Hexagonal/Trigonal
+
+
+ pinacoid / basal
+ {'{'}001{'}'}
Hexagonal/Trigonal
- {'{'}0001{'}'}
- Basal pinacoid
+ rhombohedron
+ {'{'}101{'}'}
+ Trigonal
+
+
+ dipyramid
+ {'{'}101{'}'}
Hexagonal/Trigonal
- Combining Forms
+
+
+
+
+
+
+
+
+ Combining Forms
+
+ Use + to combine multiple crystal forms into a single crystal:
+
+
+
+
+
+
+
+ Twin Laws
+
+
+ Crystal twinning is specified with the | twin(law) syntax after
+ the form list. The pipe | separates the forms from the twin specification.
+
+
+
+
+ Named Twin Laws
+
+
+
+
+ Law
+ Description
+
+
+
+
+ spinel / spinel_law
+ Contact twin on {'{'}111{'}'} (diamond, spinel)
+
+
+ brazil
+ Optical twin in quartz (left/right hand)
+
+
+ dauphine
+ Penetration twin in quartz (180° about c-axis)
+
+
+ japan
+ Contact twin in quartz (~84.5°)
+
+
+ carlsbad
+ Penetration twin in feldspar
+
+
+ baveno
+ Contact twin in feldspar
+
+
+ manebach
+ Contact twin in feldspar
+
+
+ albite
+ Polysynthetic twin in plagioclase
+
+
+ pericline
+ Polysynthetic twin in plagioclase
+
+
+ fluorite
+ Interpenetrating cube twin
+
+
+ iron_cross
+ Pyrite cross twin
+
+
+ trilling
+ Cyclic triplet twin (chrysoberyl)
+
+
+ staurolite_60
+ 60° cross twin
+
+
+ staurolite_90
+ 90° cross twin
+
+
+ gypsum_swallow
+ Swallowtail twin in gypsum
+
+
+
+
+
+
+
+
+ Modifications
+
+
+ Morphological modifications alter the crystal shape. They follow the form list,
+ separated by a pipe |. Each takes the form type(param:value).
+
+
+
+
+ Modification Types
+
+
+
+
+ Type
+ Syntax
+ Description
+
+
+
+
+ elongate
+ elongate(axis:ratio)
+ Stretch along an axis (a, b, or c)
+
+
+ flatten
+ flatten(axis:ratio)
+ Compress along an axis
+
+
+ truncate
+ truncate(form:depth)
+ Cut corners or edges by a form
+
+
+ taper
+ taper(direction:factor)
+ Narrow in one direction
+
+
+ bevel
+ bevel(edges:width)
+ Add beveled edges
+
+
+
+
+
+
+
+
+ Comments (v1.1)
+
+ CDL supports three comment styles, stripped before parsing:
+
+
+
+
+
+
+ Style
+ Syntax
+ Purpose
+
+
+
+
+ Line comment
+ # text
+ Ignored during parsing
+
+
+ Block comment
+ /* text */
+ Multi-line ignored content
+
+
+ Doc comment
+ #! Key: Value
+ Extracted as structured metadata
+
+
+
+
+
+ Doc comments (#!) are preserved in the parsed output as structured metadata
+ and can carry mineral names, habits, or other descriptive information.
+
+
+
+
+
+
+ Features (v1.2)
+
+
+ Features annotate individual crystal forms with surface markings, growth patterns,
+ inclusions, or colour properties. Features are placed in square brackets [...]
+ immediately after the form's Miller index and optional scale.
+
+
+
+
+ Feature Types
+
+
+
+ Growth
+ phantom, sector, zoning, skeletal, dendritic
+
+
+ Surface
+ striation, trigon, etch_pit, growth_hillock
+
+
+ Inclusions
+ inclusion, needle, silk, fluid, bubble
+
+
+ Colour
+ colour, colour_zone, pleochroism, lamellar, banding
+
+
+
+
+
+
+
+ Phenomena (v1.2)
+
+
+ Optical phenomena are crystal-level annotations (not per-form).
+ They follow the form list (and any modifications or twin), separated by |,
+ using the syntax phenomenon[type:value].
+
+
+
+
+ Phenomenon Types
+
+
+
+
+ Type
+ Description
+ Example Gems
+
+
+
+
+ asterism
+ Star effect (4, 6, or 12 rays)
+ Star sapphire, star ruby
+
+
+ chatoyancy
+ Cat's eye band
+ Chrysoberyl cat's eye
+
+
+ adularescence
+ Billowy internal glow
+ Moonstone
+
+
+ labradorescence
+ Spectral colour play on cleavage planes
+ Labradorite
+
+
+ play_of_color
+ Spectral flashes from diffraction
+ Opal
+
+
+ colour_change
+ Hue shift under different lighting
+ Alexandrite
+
+
+ aventurescence
+ Spangled glitter from inclusions
+ Sunstone, aventurine
+
+
+ iridescence
+ Rainbow colours from thin-film interference
+ Rainbow quartz
+
+
+
+
+
+
+
+
+ Grouping (v1.3)
+
+
+ Parenthesized groups allow shared features to be applied to multiple forms at once.
+ Features placed after the closing parenthesis apply to all forms in the group.
+
+
+
+
+
+ When flat_forms() is called on the parsed result, group features are
+ merged into each child form. In the last example above, the {'{'}111{'}'} form
+ would have both trigon:dense (its own) and phantom:3 (from the group).
+
+
+
+
+
+
+ Labels (v1.3)
+
+
+ Labels assign descriptive names to forms or groups using a label: prefix.
+ This is useful for documenting which form plays what role in the crystal.
+
+
+
+
+
+ Named forms (like octahedron, prism) are not treated as
+ labels — they are resolved to their Miller indices directly. Labels must be identifiers
+ that are not known named forms.
+
+
+
+
+
+
+ Definitions (v1.3)
+
+
+ Named definitions let you assign a form expression to a name with @name = expr,
+ then reference it with $name. Definitions are resolved by text substitution
+ before parsing. They must appear on their own lines before the main CDL expression.
+
+
+
+
+
+ Referencing an undefined name raises a parse error.
+ Definitions are stored on the parsed result for inspection by tools.
+
- Use + to combine multiple crystal forms:
+
+
+
- Full Grammar
-# Quartz with prism and rhombohedra
-trigonal[-3m]:{10-10}@1.0 + {10-11}@0.8 + {01-11}@0.9`} />
+ The complete CDL grammar, expressed as a production rule summary:
- The @distance value controls how "developed" each form is. Smaller distances result in larger face areas.
+ Examples
+form_list = form_or_group ('+' form_or_group)*
+form_or_group = label? '(' form_list ')' features? # group
+ | label? form # single form
- Diamond (Octahedron)
-
+form = (named_form | '{' miller '}') ['@' scale] features?
+features = '[' feature (',' feature)* ']'
+feature = name ':' value (',' value)*
- Fluorite (Cube with Octahedron)
-
+modifiers = ('|' modification_list)? ('|' twin)? ('|' phenomenon)?
+modification_list = modification (',' modification)*
+modification = type '(' param ':' value ')'
+twin = 'twin' '(' (law [',' count] | '[' axis ']' ',' angle) ')'
+phenomenon = 'phenomenon' '[' type [':' value] (',' param ':' value)* ']'
- Beryl (Hexagonal Prism with Pinacoid)
-
+label = IDENTIFIER ':'
+miller = INTEGER{3..4}
+scale = NUMBER
+name, type = IDENTIFIER
+value = NUMBER | IDENTIFIER`} />
- Quartz
-
+
+
+
- Extensions
+ Processing Order
- Twin Laws
- Add twin laws with the twin: modifier:
-
+ CDL text is processed through these stages:
- Modifications
- Apply modifications like elongation or flattening:
-
+
+ - Doc comment extraction —
#! lines are captured as metadata
+ - Comment stripping —
# and /* */ are removed
+ - Definition pre-processing —
@name = ... lines are extracted and $name references are resolved by text substitution
+ - Lexing — remaining text is tokenized
+ - Parsing — tokens are parsed into the AST: system, point group, form tree, modifications, twin, phenomenon
+ - Validation — point group checked against system
+
Try it yourself
diff --git a/src/pages/docs/cli-options.astro b/src/pages/docs/cli-options.astro
index 9a08bc4..2e6f440 100644
--- a/src/pages/docs/cli-options.astro
+++ b/src/pages/docs/cli-options.astro
@@ -7,7 +7,7 @@ import { Container, Button } from '../../components/ui-astro';
Complete reference for all command-line flags and options available in the
- crystal-render command.
+ cdl and mineral-db commands.
- Basic Usage
+ cdl Command
- [OUTPUT_FILE]`} />
+
- Input Options
+ Commands
- Option
+ Command
Description
- Default
+ Example
- CDL_EXPRESSION
- CDL expression to render (positional argument)
- Required
-
-
- -p, --preset NAME
- Use a preset from mineral database instead of CDL
- -
+ parse
+ Parse a CDL expression and display the result
+ cdl parse "cubic[m3m]:{'{'}111{'}'}"
- -f, --file PATH
- Read CDL expression from file
- -
-
-
- --list-presets
- List all available mineral presets
- -
+ validate
+ Validate a CDL expression (exit code 0 = valid)
+ cdl validate "cubic[m3m]:{'{'}111{'}'}"
- Output Options
+ Options
Option
Description
- Default
- OUTPUT_FILE
- Output file path (positional argument)
- crystal.svg
-
-
- --format FORMAT
- Output format: svg, stl, gltf, gemcad
- Inferred from extension
+ --json
+ Output parsed result as JSON (with parse command)
- --stdout
- Write output to stdout instead of file
- false
-
-
-
-
- View Options
-
-
-
-
- Option
- Description
- Default
+ --list-systems
+ List all 7 crystal systems with their default point groups
-
-
- --elevation DEGREES
- View elevation angle (0-90)
- 30
+ --list-point-groups
+ List all 32 point groups organized by crystal system
- --azimuth DEGREES
- View azimuth angle (-180 to 180)
- -45
+ --list-forms
+ List all named forms with their Miller indices
- --zoom FACTOR
- Zoom factor (0.5-5.0)
- 1.0
+ --list-twins
+ List all registered twin laws
- --ortho
- Use orthographic projection
- true
+ --version
+ Show cdl-parser version
- --perspective
- Use perspective projection
- false
+ --help
+ Show help message
- SVG Options
+ Parse Output
+
+ The parse command displays:
+
+ - Crystal system and point group
+ - Forms with Miller indices and scale values
+ - Modifications (if any)
+ - Twin specification (if any)
+ - Reconstructed CDL string
+
+
+
+
+ With --json, the output is a structured JSON object:
+
+
+
+ mineral-db Command
+
+
+
+ Query Options
Option
Description
- Default
+ Example
- --width PIXELS
- SVG width
- 400
-
-
- --height PIXELS
- SVG height
- 400
+ --list [CATEGORY]
+ List all presets, or filter by crystal system
+ mineral-db --list cubic
- --face-color COLOR
- Face fill color (hex or name)
- #0ea5e9
+ --info NAME
+ Show detailed info for a preset
+ mineral-db --info diamond-octahedron
- --edge-color COLOR
- Edge stroke color
- #0369a1
+ --search QUERY
+ Search presets by name, mineral, or chemistry
+ mineral-db --search beryl
- --edge-width PIXELS
- Edge stroke width
- 1.5
+ --json NAME
+ Output preset data as JSON
+ mineral-db --json quartz
- --opacity VALUE
- Face opacity (0.0-1.0)
- 0.85
+ --categories
+ List all preset categories with counts
+ mineral-db --categories
- --gradient
- Apply lighting gradient to faces
- true
-
-
- --no-gradient
- Use flat shading
- -
+ --count
+ Show total number of presets
+ mineral-db --count
- Display Options
+ Synthetic and Simulant Options
Option
Description
- Default
+ Example
- --axes
- Show crystallographic axes
- false
+ --synthetics [METHOD]
+ List synthetic minerals, optionally filtered by growth method (flux, cvd, hpht, etc.)
+ mineral-db --synthetics flux
- --grid
- Show reference grid
- false
+ --simulants [TARGET]
+ List simulant minerals, optionally filtered by target mineral
+ mineral-db --simulants diamond
- --labels
- Show face labels (Miller indices)
- false
+ --counterparts NAME
+ Show all synthetics and simulants for a natural mineral
+ mineral-db --counterparts diamond
- --title TEXT
- Add title below crystal
- -
+ --origin TYPE
+ Filter --list by origin: natural, synthetic, simulant, composite
+ mineral-db --list --origin synthetic
- 3D Export Options
+ Other Options
Option
Description
- Default
- --scale FACTOR
- Scale factor for STL/glTF output
- 10.0
-
-
- --units UNIT
- STL units: mm, cm, in
- mm
+ --version
+ Show mineral-database version
- --binary
- Use binary STL format
- true
-
-
- --ascii
- Use ASCII STL format
- false
+ --help
+ Show help message
Examples
- Basic rendering
-
- CDL Parser
-# Render preset to SVG
-crystal-render --preset quartz quartz.svg`} />
+ Custom styling
+# Parse combination with JSON output
+cdl parse "cubic[m3m]:{111}@1.0 + {100}@1.3" --json
-
+# List all named forms
+cdl --list-forms
- 3D export
+# List twin laws
+cdl --list-twins`} />
- Mineral Database
-# Export for web visualization
-crystal-render --preset zircon zircon.gltf`} />
+ View angles
+# Get detailed info
+mineral-db --info ruby-hexagonal
-
+# Find diamond counterparts
+mineral-db --counterparts diamond
- Batch processing
+# List composites
+mineral-db --list --origin composite
-
+# Export as JSON for scripting
+mineral-db --json diamond-octahedron | python -c "import sys,json; d=json.load(sys.stdin); print(d['cdl'])"`} />