Lucidchart and Lucidspark support using custom, user generated shapes. Custom shapes can be made through the Extension API which will produce
The Extension API allows users and developers to build custom shape libraries that can be distributed to select Lucid users, to all users in their Lucid account, or to all Lucid users via the Lucid Marketplace. This page also describes Lucid’s custom shape format, which provides users and developers a powerful set of capabilities for creating and customizing shapes.
The purpose of this documentation is to describe the basic functionality, format, and validation of custom shapes, which should allow a user to build a custom shape library from scratch. The format is still evolving, and it is expected that this documentation will be revised over time to reflect the most up-to-date information as it relates to the custom shape format.
In general, concepts and features listed in this document are implemented and functional. However, there are a few areas which are in development and are not considered functional:
A shape library is defined in a folder that lives in an extension package. An extension package is a set of code, content, and configuration for Lucid products that is installable. Extension packages can be distributed via Lucid’s Developer Portal, and can have one or more shape libraries. Instructions for creating extension packages can be found in the Extension API documentation.
A shape library contains custom shapes, and they can be created through the Extension API, which will be covered below. A custom shape contains two key pieces:
{
// No quotes on the value below.
a: b
c: ["d", "e", "f"]
g: 123
}
All code files in the custom shape format allow HJSON, a superset of JSON which allows comments, unquoted object keys, and flexibility around commas.
Note the missing trailing commas and the unquoted string value for
This actually represents an object with the key/value pair of
For more information about the HJSON format, see https://hjson.org/.
Creating and testing shape libraries through the Extension API requires using commands from Lucid's CLI and editing files directly. To start, you can create a shape library using the following command in an existing package:
npx lucid-package create-shape-library <name>
This will create a shape library with one custom shape (a simple rectangle) and a default
In a new shape library directory, you will have the following structure:
> my-library
> images
└── ...
> shapes
└── first.shape
└── library.manifest
{
"properties": [],
"geometry": [
{
"type": "rect"
}
]
}
The
The
The
{
"name": "Test Library",
"shapes": [
{
"shape": "first",
"name": "Test Shape",
"defaults": {
"fillColor": "#ff0000",
"strokeColor": "#00ffff",
"strokeWidth": 3,
"width": 300,
"height": 300
}
}
]
}
Property | Description |
---|---|
|
string or TranslatableString The name of the shape library |
|
ShapeEntry[] The list of shapes in this shape library. Only shapes in this list are shown |
Property | Description |
---|---|
|
string The basename for the shape file, found in |
|
string (optional) If specified, can be used to differentiate between multiple shape entries with the same |
|
string or TranslatableString The name displayed for this shape in the shape library |
|
ShapeDefaults Default block properties, like width, height, fill, etc. |
|
Default values for custom shape data, defined in the shape definition |
Property | Description |
---|---|
|
number The initial shape width |
|
number The initial shape height |
|
The initial shape rounding |
|
The initial fill color for the shape |
|
The initial line color for the shape |
|
The initial line width for the shape |
|
The initial opacity for the shape |
|
The initial rotation for the shape |
|
fixed aspect ratio. See also |
|
Starting url link on the shape |
Property | Description |
---|---|
|
string The fallback value to display if the i18n value is not found |
|
string The i18n key from the i18n files |
Any time you are running
Custom shapes are kept up to date as you make code changes to the shape definitions. You do not need to reload the page to see your changes, but note that shapes on the canvas will not be updated.
A shape definition describes the components needed to render a shape. At the most basic level, a shape definition provides the geometry of the shape, which allows Lucidchart to produce path data. More complex shapes can contain sub-shapes that each have their own unique geometry, as well as sub-shapes of their own.
The manifest file defines the name and defaults for your shape:
{
"name": "Test Library",
"shapes": [
{
"shape": "first",
"name": "Test Shape",
"defaults": {
"aspectRatio": .5,
"fillColor": "#ff0000",
"link": "your.url.com",
"opacity": .5,
"rotation": 1.5,
"strokeColor": "#00ffff",
"strokeWidth": 3,
"height": 300,
"width": 600
}
}
]
}
Shape files are defined with JSON (or HJSON):
{
"locked": ["aspectRatio"],
"images": {
"imageReference": {
"path": "file",
"type": "file",
},
},
"geometry": [
{
"type": "rect",
},
],
"style": {
"fill": {
"type": "image",
"ref": "imageReference",
"mode": "stretch",
},
},
}
A shape's geometry, which is defined through a shape definition, is what creates the data that is rendered to the screen. Geometry can be created from a standard geometric shape, a custom path, or a combination of the two (achieved with boolean operations). Geometry is drawn using relative coordinates, which are defined based on the bounds of the shape that the geometry is contained in (either a sub-shape or a rectangle if it is top-level geometry).
For complex geometry, formulas can be used to determine whether or not to include the geometry in the shape's render output. Conditional geometry evaluates the formula and if the result is false, the geometry is not rendered. These formulas work for standard shapes, paths, and boolean operations.
Geometry that is made up of multiple instances of the same shape can be defined using formulas. This is true even when those shapes have different sizes or positions (e.g. a venn diagram). There are two ways to use repeating geometry:
Property | Description |
---|---|
|
|
|
|
|
number or formula |
|
number or formula |
|
|
Property | Description |
---|---|
|
|
|
|
|
string |
|
number[] |
All geometry defined in the custom shape format follows this general schema:
{
"type": "rect",
"repeat": {
"min": 5,
"max": 20
},
"localFill": false
}
Property | Description |
---|---|
|
string The type of geometry. Options: rect, ellipse, polygon, path, BooleanOperation |
|
A formula which controls whether or not the geometry is included in the output. |
|
|
|
Defines whether or not this geometry starts a gradient. |
|
Allows local definition of formula (see Definitions below). |
Each gemoetry type is explained in detail below:
Property | Description |
---|---|
|
'rect' |
|
|
|
|
|
|
|
|
|
The x-coordinate of this rectangle, relative to its bounds (default: 0) |
|
The y-coordinate of this rectangle, relative to its bounds (default: 0) |
|
The width of this rectangle, relative to its bounds (default: 1) |
|
The height of this rectangle, relative to its bounds (default: 1) |
{
type: "rect"
// NOTE: Unspecified x and y default to 0.
// NOTE: Unspecified w and h default to 1.
}
{
type: "rect",
x: 0.5,
y: 0.5,
w: 0.5,
h: 0.5
}
Property | Description |
---|---|
|
'ellipse' |
|
|
|
|
|
|
|
|
|
The x-coordinate of this rectangle, relative to its bounds (default: 0) |
|
The y-coordinate of this rectangle, relative to its bounds (default: 0) |
|
The width of this rectangle, relative to its bounds (default: 1) |
|
The height of this rectangle, relative to its bounds (default: 1) |
{
type: "ellipse"
}
Property | Description |
---|---|
|
'polygon' |
|
|
|
|
|
|
|
|
|
number or formula The number of sides of this polygon |
|
The x-coordinate of this rectangle, relative to its bounds (default: 0) |
|
The y-coordinate of this rectangle, relative to its bounds (default: 0) |
|
The width of this rectangle, relative to its bounds (default: 1) |
|
The height of this rectangle, relative to its bounds (default: 1) |
{
type: "polygon"
n: 6
}
{
type: "polygon",
n: 5,
inset: 0.5,
w: 0.5,
h: 0.5
}
Property | Description |
---|---|
|
'path' |
|
|
|
|
|
|
|
|
|
interpolated string The defined path of the Path geometry. Uses SVG paths and assumes relative coordinates. |
{
type: "path",
path: "M 0 0 L 1 1 L 0 1 Z"
}
You can learn more about SVG paths online
Boolean geometry operations require the geometry it operates on to be defined:
Property | Description |
---|---|
|
'union', 'intersection', 'difference', 'xor' |
|
|
|
|
|
|
|
|
|
Geometry[] The geometry used in the Boolean operation |
{
type: "union",
geometry: [
{ type: "ellipse",
x: 0.25,
w: 0.75,
h: 0.75
}
{ type: "ellipse",
y: 0.25,
w: 0.75,
h: 0.75
}
]
}
{
type: "intersection",
geometry: [
{ type: "ellipse",
x: 0.25,
w: 0.75,
h: 0.75
}
{ type: "ellipse",
y: 0.25,
w: 0.75,
h: 0.75
}
]
}
{
type: "difference",
geometry: [
{ type: "ellipse",
x: 0.25,
w: 0.75,
h: 0.75
}
{ type: "ellipse",
y: 0.25,
w: 0.75,
h: 0.75
}
]
}
{
type: "xor",
geometry: [
{ type: "ellipse",
x: 0.25,
w: 0.75,
h: 0.75
}
{ type: "ellipse",
y: 0.25,
w: 0.75,
h: 0.75
}
]
}
Geometry is rendered using a styling defined within the shape definition or the sub-shape. The highest-level style is used unless it is overridden by a lower-level style. So, for example, if the style is only defined in the top-level of the shape definition, all geometry in sub-shapes would be rendered using that same style.
The style defines the formatting used to render the sub-shape's geometry. There are 3 main aspects of the style formatting that can be changed:
Property | Definition |
---|---|
|
StrokeSpecifies the geometries' line color and line size. |
|
Specifies the fill type of the geometries.This can be a solid color ( |
|
Specifies rounding that is applied to the geometries when rendering. A rectangle with rounding set will be rendered as a rounded rectangle. |
|
Indicates whether top-level geometry or subshapes are rendered first. |
{
"images": {
"image1": { "type": "file", "path": "image1.png" }
"image2": { "type": "url", "path": "https://www.website.com/image2.jpg" }
"image3": { "type": "file", "path": "image3.jpg" }
},
}
Images referenced in image fills must be added into the shape's image map within the shape definition in order to identify where the image file comes from (either a URL or internal image added to the LCSZ file).
The image map is a collection of names which reference an image file or URL; the names are then referenced within the image fills themselves.
In a shape definition, you can add a new field:
Property | Description |
---|---|
|
|
|
string Indicates either the URL of the image or the filename for internal images (e.g. |
A rectangle styled with a red fill and a 3 pixel blue stroke and no rounding
{
style: {
fill: { type: 'color', color: '#ff0000' }
stroke: { color: '#0000ff', width: 3 }
rounding: 0
}
geometry: [
{ type: rect }
]
}
A rectangle with an image fill using an internal image file
{
...
images: {
"logo": {
type: 'file'
path: 'logo.png'
}
}
...
style: {
fill: {
type: 'image'
ref: 'logo'
mode: 'stretch'
}
stroke: { color: '#00000000', width: 1 }
rounding: 0
}
geometry: [
{ type: rect }
]
}
A rectangle styled with a transparent fill and a 1 pixel black stroke and 10px rounding
{
style: {
fill: { type: 'color', color: '#00000000' }
stroke: { color: '#000000', width: 1 }
rounding: 10
}
geometry: [
{ type: rect }
]
}
The top-level shape definition can provide geometry, but oftentimes having smaller sub-shapes within the shape definition can simplify the definition and allow for more interesting shapes. Sub-shapes have a similar definition as the top-level shape definition, but allow for some additional functionality, such as condition rules, repeating rules, and configurable bounds.
If a sub-shape should only be shown under certain conditions, a condition can be defined which will only display the sub-shape(s) when the condition evaluates to true. This is useful to enable things like badges which are only displayed under certain conditions. If the conditional expression is false, the sub-shape is not rendered at all.
Sub-shapes can be repeated in a similar way as geometry, using
Lucid products will calculate the placement and size of a shape's geometry using the bounds of the shape (or sub-shape) definition that contains it. By default, the bounds of a parent shape will be applied to its sub-shapes, but you can use shape data or another formula to modify a sub-shape’s bounds and describe a new position or size for the sub-shape's geometry. Bounds is defined by specifying four parts: Anchor Position, Anchor Offset, Size, and Rotation.
Property | Description |
---|---|
|
formula |
|
formula |
|
formula |
|
formula |
|
|
|
|
|
|
Property | Description |
---|---|
|
number |
|
number |
The anchor position of a shape’s bounds specifies the anchor/rotation point for the shape. Combined with the anchor offset, anchor position dictates where to place the shape relative to its container. If an anchor position is not defined for the shape, it will default to anchoring to the top-left corner of its parent container.
Anchor position is defined using relative or absolute coordinates. See the Absolute vs. Relative Coordinates section below to learn more.
The anchor offset of a shape’s bounds describes where the anchor position will be placed on the shape. For example, an anchor offset of top-left will place its top-left corner at the anchor position.
Anchor offset can be specified directly as a relative coordinate within the sub-shape [from
As an illustration, in the example below there are 3 sub-shapes (A, B, and C), each with different anchor types and positions.
The following values of each sub-shape's anchor offset are as follows:
Note that changing the anchor offset would move each sub-shape around their respective green points, and not the container itself.
Anchor Type | Description |
---|---|
top-left | Uses the top-left corner of the sub-shape as the anchor point. Equivalent to an anchor of |
top | Uses the top center point of the sub-shape as the anchor point. Equivalent to an anchor of |
top-right | Uses the top-right corner of the sub-shape as the anchor point. Equivalent to an anchor of |
left | Uses the left center point of the sub-shape as the anchor point. Equivalent to an anchor of |
center | Uses the center of the sub-shape as its anchor point. Equivalent to an anchor of |
right | Uses the right center point of the sub-shape as the anchor point. Equivalent to an anchor of |
bottom-left | Uses the bottom-left corner of the sub-shape as the anchor point. Equivalent to an anchor of |
bottom | Uses the bottom center point of the sub-shape as the anchor point. Equivalent to an anchor of |
bottom-right | Uses the bottom-right corner of the sub-shape as the anchor point. Equivalent to an anchor of |
The size of a shape’s geometry describes the width and height of the shape, specifying the extent of the shape’s bounds. Like anchor position, shape size can be specified using absolute or relative values. See the Absolute vs. Relative Coordinates section below to learn more.
A shape’s bounds can specify a rotation, which will be applied to shapes after they are rendered, using the anchor point as the point of rotation. The geometry itself operates purely on a non-rotated coordinate system for simplicity.
You can use absolute or relative coordinates to specify anchor position and shape size.
Absolute coordinates are measured in pixels in screen space. When you use absolute coordinates to specify anchor position, you are placing the anchor point at an exact pixel location. Absolute coordinates are measured relative to the parent bounds. For example, if the absolute position
Relative coordinates specify a percentage of the bounds in which the shape is contained. Relative coordinates are always in the range 0 to 1, with relative coordinates
Anchor positions are specified as x and y in the bounds, and are made absolute by including the characters
bounds: {
x: 5
y: 5
w: 5
h: 5
anchor: 'top-left'
// All coordinates are absolute.
// "absolute: true" is equivalent.
absolute: 'xywh'
}
bounds: {
x: 0.5
y: 0.5
w: 5
h: 5
anchor: 'center'
// Width and Height are absolute
absolute: 'wh'
}
bounds: {
x: 0,
y: 0.5,
w: 0.5,
h: 0.5,
anchor: 'left',
// None of the properties are absolute.
// - "absolute: ''" is equivalent.
// - No absolute field is also equivalent.
absolute: false
}
bounds: {
x: 1
y: 1
w: 25
h: 25
anchor: 'bottom-right'
absolute: 'wh'
}
bounds: {
x: 0.5
y: 0.5
w: 0.9
h: 0.9
anchor: 'center'
}
You can use formulas in your shape definition to conditionally display and/or repeat a geometry or sub-shape description.
You can apply formulas to field values in your shape definitions to make the values change dynamically with data. Documentation for the Lucid formula system can be found online on Lucid's help site Use formulas in Lucidchart or in the internal documentation.
In the custom shape format, formula expressions always start with
You can add interpolated string values of the form
For example, when the string:
"Here is 1 + 2: {{=1 + 2}}"
is evaluated, it will produced the string:
"Here is 1 + 2: 3"
Shape data can be defined on a custom shape to allow users to configure the data used by the custom shape. Shape data can be used in any formula within the shape, using the syntax
Property | Description |
---|---|
|
string The internal name of the field, used in formulas. |
|
string or TranslatableString The label displayed when the shape property is shown in the editor. |
|
The type of data this field stores. |
|
The default value for the field. This can be a formula or a constant value. |
|
Constraints which determine whether or not the property is valid. |
Property | Description |
---|---|
|
formula The condition checked for the constraint, which fails when this evaluates to false. |
|
The value used to resolve this constraint when it fails. |
|
The message shown to the user when the constraint fails. |
Property Type | Description | Example |
---|---|---|
boolean | True or false. |
|
number | A number value, including both integers and decimal values. |
|
string | A text value. |
|
color | A color value, constructed using color functions or a hex color. |
|
date | A date value, constructed using date functions. |
|
picklist | A value selected from a list of possible values, displayed in the editor as a picklist. The value must be one of the available values in the.picklist. | |
array | Multiple data values supplied as an array. Can be constructed using array functions. |
|
object | A collection of key-value pairs. Can be constructed using object functions. |
|
formula | Allows any formula value. |
|
Shape data properties can have an optional list of constraints which restrict the values of data allowed. For example, a percentage field could have a constraint where the value must be less than or equal to 100.
Constraints do not prevent saving shape data, but rather will indicate the value is invalid and allow an optional resolution value, which is used in place of the specified value. In the above example, if the percentage field exceeds 100, the resolution value might be 100 (i.e. if the value were to go above 100, then the resolution value (100) is used instead). If no resolution is provided, the shape will be shown as an error state.
Definitions can be used to simplify complex calculations by storing data to be referenced in formulas. These definitions act like shape data properties that are not editable and are purely calculated using other values.
For example, if a shape data property named
Definitions can be defined in the top-level of the shape definition, making it available to all geometry and sub-shape, or within a sub-shape, which would be available to that sub-shape's geometry and further sub-shapes.
Property | Description |
---|---|
|
string |
|
formula |
Definitions must be defined with a data type, using one of the data types described in the shape data properties section above.
As definitions are created, they are available for use within the shape they are defined in or any sub-shapes below that shape. This is referred to as the scope of the variable, which describes where the variable may be used. The scope for sub-shapes in called a child scope or a lower scope, and the scope of the parent sub-shape (or top-level shape definition) is called a parent scope or a higher scope.
As an example, in the following figure there are 3 scopes (A, B, and C):
There are some exceptions to the general rule that definitions are available within the shape they are defined in, when working with sub-shapes. This is due to the order in which formulas are evaluated when generating the geometry to render the shape definition.
Formulas in a shape definition are evaluated in the following order:
When using formulas in the custom shape format, there are some properties that are pre-filled with metadata about the shape. These can be used anywhere in the custom shape format and will always be available (unless overridden with a definition of the same name).
Definition | Description |
---|---|
|
The width of the shape in pixels. |
|
The height of the shape in pixels. |
Text can be displayed on the shape using text areas. Text areas are defined in either the shape definition or in sub-shapes, which fill the bounds in which it is defined. Sub-shapes containing only text can be defined to place text on a specific area of the overall shape.
Text areas only define the placement and rendering of text. If a border is needed for a text area, for example, additional geometry must be used.
Property | Description |
---|---|
|
string this must be unique |
|
string or formula |
|
|
|
|
|
|
|
|
|
|
Property | Description |
---|---|
|
|
|
|
|
|
|
|
Property | Description |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
In some cases, shape geometry may need to be clipped to fit to a specific outline. For example, a movie ranking shape (i.e. rating that uses stars) could be constructed using a rectangle shape that grows based on the value, which is then clipped to a shape consisting of the 5 stars.
Clipping for a shape is performed by taking all geometry created for the shape (both geometry in the shape and that shape's sub-shapes) and intersecting it with the clipping mask defined by the shape clipping settings.
Property | Description |
---|---|
|
Geometry[] |
|
|
Clipping removes all geometry that falls outside of the clipping path, but sometimes a geometry that equals the clipping path is needed. For example, in the star rating example above, if you want a line to be placed around each star, you would need to add new geometry that matches the same path as the clip path. Instead, a stroke can be added to the clipping path which adds the extra geometry with the specific stroke settings without needing a separate copy of the geometry.
Property | Description |
---|---|
|
string or formula |
|
string or formula |
|
string or formula |
Shape constraints allow the shape to define limits that prevent the shape from going below a minimum size or above a maximum size. For both minimum and maximum size, both width and height are optional, so it is possible to have a shape that is limited in only one dimension in either direction or has different limits for height and width. Shape constraints also allow locking controls on the shape. The shapes horizontal or vertical resizing can be limited to prevent the shape from being resized in that dimension. Minimum size can be specified using a formula, which allows the minimum dimensions of the shape to be dynamically updated based on formula values. If resizing is also locked for that dimension, the shape's dimension will be fully dynamic. Lastly, you are able to alter the image that represents your shape in the shapes panel. This is useful if you have many shapes that look the same or have the same structure, but serve a different purpose.
Property | Description |
---|---|
|
A constraint that limits the minimum size of the shape. |
|
A constraint that limits the minimum size of the shape. |
|
A list of fields to lock. Options are |
|
An SVG that replaces the thumbnail image of the shape in the toolbar. |
Property | Description |
---|---|
|
|
|
|
Property | Description |
---|---|
|
If present, constrains the width to this number |
|
If present, constrains the height to this number |
{
properties: [
{
name: 'Min', label: 'Min', type: 'number', default: 1,
constraints: [{ condition: '=@Min < @Max', message: 'Min constraint' }]
}
{
name: 'Max', label: 'Max', type: 'number', default: 100,
constraints: [{condition: '=@Max > @Min', message: 'Max constraint' }]
}
{
name: 'Value', label: 'Value', type: 'number', default: 20,
constraints: [
{ condition: '=@Value >= @Min', resolution: '=@Min', message: 'Min value constraint' }
{ condition: '=@Value <= @Max', resolution: '=@Max', message: 'Max value constraint' }
]
}
{ name: 'Foreground', label: 'Foreground', type: 'color', default: '=fillColor()' },
{ name: 'Background', label: 'Background', type: 'color', default: '#D7E9FF' }
]
defs: [
{ name: 'Rounded', type: 'number', value: '=@Height / @Width' }
]
clip: {
geometry: [
{ type: 'union'
geometry: [
{ type: 'ellipse', w: '=@Rounded' }
{ type: 'rect', x: '=@Rounded / 2', w: '=1 - @Rounded' }
{ type: 'ellipse', x: '=1 - @Rounded', w: '=@Rounded' }
]
}
]
}
shapes: [
// Background
{
style: { fill: { type: 'color', color: '=@Background' } }
geometry: [{ type: 'rect' }]
}
// Progress
{
style: { fill: { type: 'color', color: '=@Foreground' } }
geometry: [
{ type:'rect', w: '=(@Value - @Min) / (@Max - @Min)' }
]
}
]
}
The rounded progress bar defines a shape which represents a progress bar with rounded edges showing a current value in a range defined by the user as shape data. This example uses clipping to ensure that the path doesn't warp when resized and to simplify the geometry used in the progress bar.
{
properties: [
{
name: 'Min',
label: 'Min',
type: 'number',
default: 0,
constraints: [{
condition: '=@Min < @Max',
message: 'Max must be larger than Min'
}]
},
{
name: 'Max',
label: 'Max',
type: 'number',
default: 100,
constraints: [{
condition: '=@Max > @Min',
message: 'Max must be larger than Min'
}]
},
{
name: 'Value',
label: 'Value',
type: 'number',
default: 70,
constraints: [
{
condition: '=@Value >= @Min',
resolution: '=@Min',
message: 'Value must be greater or equal to Min'
},
{
condition: '=@Value <= @Max',
resolution: '=@Max',
message: 'Value must be less or equal to Max'
}
],
},
{
name: 'Foreground',
label: 'Foreground',
type: 'color',
default: '=fillColor()'
},
{
name: 'Background',
label: 'Background',
type: 'color',
default: '#D7E9FF'
}
],
shapes: [
{
shapes: [
// Outer Path
{
style: {fill: {type: 'color', color: '=@Background'}}
geometry: [{type: 'rect'}]
}
// Inner Path
{
style: {fill: {type: 'color', color: '=@Foreground'}}
geometry: [{type: 'rect', w: '=(@Value - @Min) / (@Max - @Min)'}]
}
]
}
]
clip: {
geometry: [{
type: 'intersection',
geometry: [
// Triangle Path
{type: 'path', path: 'M 0,1 L 1,0 L 1,1 Z'}
{
type: 'union'
geometry: [
// Bars
{type: 'rect', x: 0, w: 0.233},
{type: 'rect', x: 0.256, w: 0.233},
{type: 'rect', x: 0.512, w: 0.233},
{type: 'rect', x: 0.767, w: 0.233},
]
}
]
}]
}
}
Shows a progress bar shape in the style of a signal strength meter. The existing shape is continuous, however the shape could be modified to round to the nearest 0.5 if needed.
{
properties: [
{ name: 'Min', label: 'Min', type: 'number', default: 0 }
{ name: 'Max', label: 'Max', type: 'number', default: 100 }
{ name: 'Value', label: 'Value', type: 'number', default: 20
constraints: [
{ condition: '=@Value >= @Min', resolution: '=@Min', message: 'Too low!' }
{ condition: '=@Value <= @Max', resolution: '=@Max', message: 'Too high!' }
]
}
{ name: 'Foreground', label: 'Foreground', type: 'color', default: '=fillColor()' }
{ name: 'Background', label: 'Background', type: 'color', default: '#D7E9FF' }
],
templates: [
{ name: 'stars'
geometry: [
{
type: union
geometry: [
{ type: 'polygon', n: 5, inset: 0.4, x: 0.0, y: 0, w: 0.2, h: 1 }
{ type: 'polygon', n: 5, inset: 0.4, x: 0.2, y: 0, w: 0.2, h: 1 }
{ type: 'polygon', n: 5, inset: 0.4, x: 0.4, y: 0, w: 0.2, h: 1 }
{ type: 'polygon', n: 5, inset: 0.4, x: 0.6, y: 0, w: 0.2, h: 1 }
{ type: 'polygon', n: 5, inset: 0.4, x: 0.8, y: 0, w: 0.2, h: 1 }
]
},
]
}
],
style: { fill: { type: 'color', color: '=@Background' } },
// Draw the background
geometry: [
{ type: 'template', template: 'stars' }
]
shapes: [
// Draw the foreground
{
style: { fill: { type: 'color', color: '=@Foreground' } },
geometry: [
{
type: intersection
geometry: [
{ type: 'template', template: 'stars' }
{ type: 'rect', w: '=(@Value - @Min) / (@Max - @Min)' }
]
}
],
},
// Outline the stars (using the foreground color darkened by 20%).
{
style: {
fill: { type: 'color', color: '#00000000' },
stroke: { color: '=DARKEN(@Foreground, 20%)', width: 1 },
},
geometry: [
{ type: 'template', template: 'stars' }
]
}
]
}
The star rating defines a shape which represents a progress bar as a star rating (in the vein of reviews). The progress bar is continuous and clips to the geometry of the stars. A discrete version could be implemented which rounds the input to the nearest 0.5 to make it map to whole or half stars.
{
properties: [
{
name: 'In',
label: 'In',
type: 'number',
default: 5,
constraints: [
{condition: '=@In > 0', resolution: 1, message: 'Must be greater than 0.'}
]
},
{
name: 'Out',
label: 'Out',
type: 'number',
default: 3,
constraints: [
{condition: '=@Out > 0', resolution: 1, message: 'Must be greater than 0.'}
]
},
],
style: {
fill: {type: 'color', color: '#f5f5f5'},
stroke: {color: '#999999', width: 2},
},
shapes: [
{ geometry: [{type: 'rect' }] }
{
repeat: {type: 'for', index: 'i', min: 1, max: '=@In', step: 1}
bounds: {x: '=@i / (@In + 1)', y: 0, w: '=1 / (@In + 1)', h: 0.2, anchor: 'top'}
style: {
fill: {type: 'color', color: '#cccccc'}
stroke: {color: '#999999', width: 2}
}
geometry: [{type: 'rect'}]
linkpoints: [ {x: 0.5, y: 0} ]
}
{
repeat: {type: 'for', index: 'i', min: 1, max: '=@Out', step: 1}
bounds: {x: '=@i / (@Out + 1)', y: 1, w: '=1 / (@Out + 1)', h: 0.2, anchor: 'bottom'}
style: {
fill: {type: 'color', color: '#cccccc'}
stroke: {color: '#999999', width: 2}
}
geometry: [{type: 'rect'}]
linkpoints: [ {x: 0.5, y: 1} ]
}
]
}
The multiplexer defines a shape that has a variable number of link points on the top and bottom, which are controlled by two shape data fields (In and Out). Link points are created using repeated shapes.
{
properties: [
{ name: 'PositiveColor', label: 'Positive Color', type: 'color', default: '#03adfc' },
{ name: 'NegativeColor', label: 'Negative Color', type: 'color', default: '#fc0362' },
{ name: 'Min', label: 'Minimum', type: 'number', default: -100 },
{ name: 'Max', label: 'Maximum', type: 'number', default: 100 },
{ name: 'Value', label: 'Value', type: 'number', default: 50 },
],
templates: [
{
name: 'bar'
geometry: [
{ type: 'rect', x: 0.5, w: '=@Value / (@Max - @Min)' },
],
}
],
shapes: [
{
style: {
fill: { type: 'color', color: '=fillColor()' }
stroke: { color: '=DARKEN(fillColor(), 20%)', width: 1 },
},
geometry: [
{ type: 'rect' },
{ type: 'path', path: 'M 0.5 0 L 0.5 1'}
],
}
{
style: {
fill: { type: 'color', color: '=IF(@Value < 0, @NegativeColor, @PositiveColor)' }
},
geometry: [
{
type: 'template'
template: 'bar'
},
],
},
],
}
{
"properties": [
{ "name": "Name", "label": "Name", type: "string", "default": "You" }
],
"style": {
"fill": { "type": "color", "color": "=fillColor" },
"stroke": { "color": "#000000", "width": 2 }
},
"shapes": [
{
"geometry": [ { "type": "rect" } ],
"textarea": {
"name": "t0",
"text": "Hello, {{=@Name}}!",
"editable": true,
"style": { "color": "#000000" }
}
}
]
}
The greeting shape is a simple example of a textarea on a shape. The shape is a simple rectangle with a fill of the current fill color, a black border, and a textarea that fills the shape.
Term | Definition |
---|---|
LCSZ | The file format this document describes. LCSZ is intended to mean Lucid Custom Shape ZIP. |
Shape Library | A collection of shape definitions, images, text translations and shape library entries stored in a ZIP file format that can be uploaded to Lucidchart as a new shape library. |
Shape Library Entry | A shape shown to a user in the list of shapes in a shape library (in Lucidchart). Each shape library entry is composed of a shape definition and a list of settings for that shape library entry; each entry can be a unique set of default properties using a single shape definition. |
Shape Definition | A file that defines the structure of a shape, properties associated to that shape and interactions. A shape definition specifies how shapes are drawn; a shape entry matches up a shape definition with it's default properties and settings. |
Shape | An entity which includes scoped definitions, geometries for rendering, and a group of subshapes. Rendering a shape renders both geometries and subshapes; the order field defines whether geometries or shapes are rendered on top or not. |
Sub-Shape | A shape contained within another shape, which can have its own render style, bounds and definitions. Sub-shapes can be contained within the shape itself, or within another sub-shape. |
Geometry | A path defined within a shape. Helpers like rect and ellipse give the user easier tools to add standard geometry to a shape. |
Top-Level Geometry | The geometry defined on shape definition itself and not in sub-shapes. |
Template | A collection of geometry that can be reused multiple times using a set of passed in parameters. |
i18n | Internationalization. Provides translations for text labels used by shapes and the shape library. Not yet implemented. |
Clipping Mask | A clipping mask defines the bounds of the shape; no geometry should be present outside of the clipping mask. At a technical level, all generated shape geometry is intersected with the clipping mask to produce the final geometry. |
Link point | A connection point that is shown when users are dragging a line to connect with the shape to allow the line to snap to a specific point. |
Textarea | A block of optionally editable text displayed for a shape. Textareas are positioned relative to the current shapes offset. |