Introduction
Comb Script is a language for describing technical vector designs and a tool that exports these designs as SVG files. A primary goal of Comb Script is to express designs naturally, so they are easier to adjust and customize.
Comb Script was inspired by OpenSCAD, CSS, HTML, and Adobe Illustrator snapping shenanigans.
Parametric
Because shapes in Comb Script can be positioned relative to the bounds of their parents, it is possible to make designs that flex when dimensions change.
Expressive
Positions can be described in multiple ways allowing more natural expression. For example you can specify that a circle is 10 units from the right side of its container and vertically centered, rather than expressing its global coordinates.
Declarative
Comb Script is more like HTML than JavaScript. Ideally, your document describes your design, not the steps required to make it.
Unstyled
Shapes in Comb Script represent only the path data and don't have their own style properties like fill-color, stroke-color, or stroke-width. Comb Script is primarily designed for designs that describe paths for laser-cutters and plotters where such styles are not needed.
Boolean Operations
Combine shapes using boolean operations: Intersection, Union, and Difference
Render to SVG
Shape data can be exported as SVG using style templates.
Basic Syntax
Comb Script documents are written in YAML, a common and human-readable data-file format. Comb Script recognizes predefined keywords to describe regions, shapes, and their properties.
Here is an example of a simple Comb Script document that draws an ellipse:
properties: width: 525 height: 225 children: - ellipse: properties: width: 200 height: 200
This example begins by defining two document properties, width
and height
that describe the dimensions of the document. If these properties are not defined, defaults will be used. Document properties are defined using the properties:
key followed by a set of indented key: value pairs.
Next, the example defines its children under the children:
key. The children are indented one level and each is prefixed with a -
to indicate a YAML array item. There are several types of children in Comb Script including regions, rectangles, and ellipses.
This document has one child, an ellipse
. The ellipse defines width
and height
properties to set its dimensions.
Regions
The basic building-blocks in Comb Script are called regions. A region describes a rectangular bounds in the drawing and and can contain child regions. Child regions are laid out in relation to the bounds of their parent.
There are several types of regions in Comb Script. The basic region
type is primarily organizational. It is used to define a new part of the drawing and to group its children. The basic region
will not generate a vector shape in the exported SVG.
The rectangle
or ellipse
region types have all the same properties of the basic region
but also draw a shape in the export.
Region Bounds
Every region has a set of bounds that describe a rectangular area in the drawing. These bounds can be set using the top
, left
, bottom
, and right
properties. These values are relative to the registration position of the region's parent.
A region's bounds can also be specified relative to the parent's bounds using margin_top
, margin_left
, margin_bottom
, and margin_right
properties.
You can specify the dimensions of the bounds with the width
and height
properties.
These properties can be mixed any way you wish, as long as they don't conflict.
children: - region: properties: top: -100 bottom: 0 margin_left: 10 width: 100
Registration
Regions can optionally set their registration position with the registration
property. The new registration position will be used by the region's children when laying out their bounds. It will also be used for the pivot point for rotations and scales applied to the region.
The default value of registration
is parent
which will keep the registration position set by the region's parent. Other values, such as 'top_left' and 'center' move it to a position determined by the region's bounds.
children: - region: properties: width: 200 height: 200 registration: top_right children: - rectangle: properties: top: 0 left: 0 width: 75 height: 75
Transformations
You can transform the coordinate system used by a region and its children using the rotation
, scale_x
, and scale_y
properties.
children: - rectangle: properties: width: 100 height: 100 rotation: 45
Children
Regions can have any number of child regions. A region's bounds, registration, and transform are used by when positioning its children. Using nesting, you can describe the positional relationships of your shapes making parts of your design parametric.
In the following example the position of the two ellipses is determined by the width of their parent.
children: - region: properties: width: 400 height: 200 children: - ellipse: properties: height: 100 width: 100 margin_left: 30 - ellipse: properties: height: 100 width: 100 margin_right: 30
Shapes
The rectangle
and ellipse
region-types will generate a shape in the export. In these examples, exported shapes are filled in.
children: - rectangle: properties: margin_left: 10 width: 200 height: 200 radius: 10 - ellipse: properties: margin_right: 10 width: 200 height: 200 radius: 20
Combining Shapes
Shapes can be combined using the boolean
property. The possible values are add
, subtract
, and intersect
.
Shapes with a set boolean
property are combined with their parent's shape. If the parent does not generate a shape the shape of the first child will be used.
children: - rectangle: properties: name: base_rectangle width: 100 height: 100 children: - ellipse: properties: name: subtract_ellipse height: 100 width: 100 left: -100 top: -100 boolean: subtract
children: - region: properties: name: parent_region width: 300 height: 200 children: - ellipse: properties: margin_left: 0 height: 200 width: 200 - ellipse: properties: margin_right: 0 height: 200 width: 200 boolean: intersect
You can use booelan operations will applied to a region's children as well. For example you can subtract many shapes from a single shape, subtract a single shape from many shapes, or even subtract many shapes from many shapes.
children: - region: properties: width: 100 height: 200 children: - ellipse: properties: margin_top: 0 height: 85 - ellipse: properties: margin_bottom: 0 height: 85 - region: properties: width: 200 height: 100 boolean: subtract children: - ellipse: properties: margin_left: 0 width: 85 - ellipse: properties: margin_right: 0 width: 85
Grids
Comb Script provides a special region-type called a region_grid
. Region grids can be used to draw a region repeatedly in a rectangular grid.
The rows
and columns
properties will set the number of rows and columns in the grid directly. You can set row_height
and column_width
instead to create as many rows or columns as needed to fill the region grid.
Each cell in the generated grid will contain a clone of the children of the region grid.
children: - region_grid: properties: width: 400 height: 200 column_width: 50 rows: 4 registration: center children: - ellipse: properties: width: 30 height: 30
YAML Repeated Nodes
YAML's repeated node feature can be used to to create named parameters and library shapes that can be used throughout your document. Repeated nodes are defined with &
followed by a name, and used with *
followed by the name. Repeated nodes are genrally defined as an array under the library:
key.
Constants
You can use repeated nodes as named constants (aka variables or parameters) to identify commonly used values in your document and create a single place in the document where they can be changed.
library: - &size 200 children: - ellipse: properties: width: *size height: *size
Library Items
It is common that you will reuse the same shape in multiple places in your document. Repeated nodes can represent entire regions, their properties, and even nested children. Each repeated node will be separately laid out in their parent's context.
library: - &ex rectangle: properties: margin_top: 10 margin_bottom: 10 width: 40 radius: 4 children: - region: properties: margin_left: 10 width: 150 height: 150 registration: center children: - *ex - region: properties: margin_right: 10 width: 100 height: 100 registration: center children: - *ex
{{class}}
-
{{#keyword}}
- keyword:
- {{keyword}} {{/keyword}} {{#extends}}
- extends:
- {{extends}} {{/extends}}
Required Properties
-
{{#required_properties}}
- {{>prop}} {{/required_properties}}
Properties
-
{{#properties}}
- {{>prop}} {{/properties}}
Inherited Properties
-
{{#inherited_properties}}
- {{>prop}} {{/inherited_properties}}
- type:
- {{type}}
- default:
- {{default}}{{^default}}undefined{{/default}} {{#required}}
- required:
- {{required}} {{/required}} {{#values.length}}
- values: {{#values}}
- {{.}} {{/values}} {{/values.length}}