diff --git a/docs/specs/constants.md b/docs/specs/constants.md
index ecc9368..b04fc90 100644
--- a/docs/specs/constants.md
+++ b/docs/specs/constants.md
@@ -157,6 +157,27 @@
{schema_enum:stroke-dash-type}
+
Matte Mode
+
+{schema_string:constants/matte-mode/description}
+
+The value for Luma is calculated accourding to [Rec.709](https://www.itu.int/rec/R-REC-BT.709) standard:
+
+$$Y = 0.2126 R + 0.7152 G + 0.0722 B$$
+
+{schema_enum:matte-mode}
+
+
+ Example
+
+ {...lottie.layers[1], shapes: [], ks: {}}
+
+
+
Gradient Type
{schema_string:constants/gradient-type/description}
diff --git a/docs/specs/layers.md b/docs/specs/layers.md
index 58858a9..b9f56f1 100644
--- a/docs/specs/layers.md
+++ b/docs/specs/layers.md
@@ -18,6 +18,42 @@ The `ty` property defines the specific layer type based on the following values:
{schema_object:layers/visual-layer}
+
+#### Mattes
+
+A matte allows using a layer as a mask for another layer.
+
+The way it works is the layer defining the mask has a `tt` attribute with the
+appropriate [value](constants.md#matte-mode).
+The layer being masked is indicated by the `tp` attribute, which has the index (`ind`) of the layer that is being masked.
+
+In this example there's a layer with a rectangle and a star being masked by an ellipse:
+
+
+
+ Example
+
+ {...lottie.layers[1], shapes: [], ks: {}}
+
+
+
+
## Layer types
diff --git a/docs/static/examples/matte.json b/docs/static/examples/matte.json
new file mode 100644
index 0000000..8e49a1e
--- /dev/null
+++ b/docs/static/examples/matte.json
@@ -0,0 +1,390 @@
+{
+"v": "5.5.7",
+"ip": 0,
+"op": 180,
+"nm": "Animation",
+"mn": "{b3d1b083-9de7-4537-a691-fc9aa42f9742}",
+"fr": 60,
+"w": 512,
+"h": 512,
+"assets": [
+],
+"layers": [
+ {
+ "ddd": 0,
+ "ty": 4,
+ "ind": 1,
+ "st": 0,
+ "ip": 0,
+ "op": 180,
+ "nm": "Ellipse (Mask)",
+ "ks": {
+ "a": {
+ "a": 0,
+ "k": [
+ 153,
+ 294
+ ]
+ },
+ "p": {
+ "a": 0,
+ "k": [
+ 346,
+ 211
+ ]
+ },
+ "s": {
+ "a": 0,
+ "k": [
+ 100,
+ 100
+ ]
+ },
+ "r": {
+ "a": 0,
+ "k": 0
+ },
+ "o": {
+ "a": 0,
+ "k": 100
+ }
+ },
+ "shapes": [
+ {
+ "ty": "el",
+ "nm": "Ellipse",
+ "mn": "{261eddeb-af92-4be1-932c-790b00c23933}",
+ "p": {
+ "a": 0,
+ "k": [
+ 137.0955223880597,
+ 293.60820895522386
+ ]
+ },
+ "s": {
+ "a": 0,
+ "k": [
+ 303.42089552238804,
+ 315.55074626865667
+ ]
+ }
+ },
+ {
+ "ty": "st",
+ "nm": "Stroke",
+ "mn": "{aa9c282c-253d-4d8d-ab05-4819c592fa85}",
+ "o": {
+ "a": 0,
+ "k": 100
+ },
+ "c": {
+ "a": 0,
+ "k": [
+ 1,
+ 1,
+ 1
+ ]
+ },
+ "lc": 2,
+ "lj": 2,
+ "ml": 0,
+ "w": {
+ "a": 0,
+ "k": 6
+ }
+ },
+ {
+ "ty": "fl",
+ "nm": "Fill",
+ "mn": "{2b2b0002-ff0c-4978-a33b-db4e0498848d}",
+ "o": {
+ "a": 0,
+ "k": 100
+ },
+ "c": {
+ "a": 0,
+ "k": [
+ 0.9411764705882353,
+ 0.11372549019607843,
+ 0.0392156862745098
+ ]
+ },
+ "r": 1
+ }
+ ],
+ "td": 1
+ },
+ {
+ "ddd": 0,
+ "ty": 4,
+ "ind": 2,
+ "st": 0,
+ "ip": 0,
+ "op": 180,
+ "nm": "Shapes (Masked)",
+ "ks": {
+ "a": {
+ "a": 0,
+ "k": [
+ 256,
+ 256
+ ]
+ },
+ "p": {
+ "a": 0,
+ "k": [
+ 256,
+ 256
+ ]
+ },
+ "s": {
+ "a": 0,
+ "k": [
+ 100,
+ 100
+ ]
+ },
+ "r": {
+ "a": 0,
+ "k": 0
+ },
+ "o": {
+ "a": 0,
+ "k": 100
+ }
+ },
+ "shapes": [
+ {
+ "ty": "gr",
+ "nm": "PolyStar",
+ "mn": "{528994b7-40ff-4d12-81f8-603f274da12e}",
+ "it": [
+ {
+ "ty": "sr",
+ "nm": "PolyStar",
+ "mn": "{ce8756d7-289f-4f84-a135-d225d57c42e0}",
+ "p": {
+ "a": 0,
+ "k": [
+ 427.2716417910448,
+ 194.29253731343283
+ ]
+ },
+ "or": {
+ "a": 0,
+ "k": 216.4160919189453
+ },
+ "ir": {
+ "a": 0,
+ "k": 87.03440856933594
+ },
+ "r": {
+ "a": 0,
+ "k": 261.54803466796875
+ },
+ "pt": {
+ "a": 0,
+ "k": 5
+ },
+ "sy": 1,
+ "os": {
+ "a": 0,
+ "k": 0
+ },
+ "is": {
+ "a": 0,
+ "k": 0
+ }
+ },
+ {
+ "ty": "st",
+ "hd": true,
+ "nm": "Stroke",
+ "mn": "{efd05a25-a43b-451d-83d2-53a477087223}",
+ "o": {
+ "a": 0,
+ "k": 100
+ },
+ "c": {
+ "a": 0,
+ "k": [
+ 0,
+ 0.5019607843137255,
+ 1
+ ]
+ },
+ "lc": 2,
+ "lj": 2,
+ "ml": 0,
+ "w": {
+ "a": 0,
+ "k": 1
+ }
+ },
+ {
+ "ty": "fl",
+ "nm": "Fill",
+ "mn": "{523ca39c-9e57-4547-bf0e-ba7496003579}",
+ "o": {
+ "a": 0,
+ "k": 100
+ },
+ "c": {
+ "a": 0,
+ "k": [
+ 0.19607843137254902,
+ 0.3137254901960784,
+ 0.6901960784313725
+ ]
+ },
+ "r": 1
+ },
+ {
+ "ty": "tr",
+ "a": {
+ "a": 0,
+ "k": [
+ 427.2716417910448,
+ 194.29253731343283
+ ]
+ },
+ "p": {
+ "a": 0,
+ "k": [
+ 338.7223880597015,
+ 209.76716417910447
+ ]
+ },
+ "s": {
+ "a": 0,
+ "k": [
+ 100,
+ 100
+ ]
+ },
+ "r": {
+ "a": 0,
+ "k": 0
+ },
+ "o": {
+ "a": 0,
+ "k": 100
+ }
+ }
+ ]
+ },
+ {
+ "ty": "gr",
+ "nm": "Rectangle",
+ "mn": "{d2d7a5d5-6d91-42e8-b40a-af52a112fe38}",
+ "it": [
+ {
+ "ty": "rc",
+ "nm": "Rectangle",
+ "mn": "{9ef8604e-7891-4909-a655-445131b4d842}",
+ "p": {
+ "a": 0,
+ "k": [
+ 209.17611940298502,
+ 226.8
+ ]
+ },
+ "s": {
+ "a": 0,
+ "k": [
+ 363.3313432835821,
+ 369.3492537313433
+ ]
+ },
+ "r": {
+ "a": 0,
+ "k": 0
+ }
+ },
+ {
+ "ty": "st",
+ "hd": true,
+ "nm": "Stroke",
+ "mn": "{444584d2-cb59-4cba-83a1-82cc605837fd}",
+ "o": {
+ "a": 0,
+ "k": 100
+ },
+ "c": {
+ "a": 0,
+ "k": [
+ 0,
+ 0.5019607843137255,
+ 1
+ ]
+ },
+ "lc": 2,
+ "lj": 2,
+ "ml": 0,
+ "w": {
+ "a": 0,
+ "k": 1
+ }
+ },
+ {
+ "ty": "fl",
+ "nm": "Fill",
+ "mn": "{f75aed67-9b0e-41a9-b859-a14b5b0a320d}",
+ "o": {
+ "a": 0,
+ "k": 100
+ },
+ "c": {
+ "a": 0,
+ "k": [
+ 0.7686274509803922,
+ 0.8509803921568627,
+ 0.9607843137254902
+ ]
+ },
+ "r": 1
+ },
+ {
+ "ty": "tr",
+ "a": {
+ "a": 0,
+ "k": [
+ 256.1910447761194,
+ 273.8149253731343
+ ]
+ },
+ "p": {
+ "a": 0,
+ "k": [
+ 256.1910447761194,
+ 273.8149253731343
+ ]
+ },
+ "s": {
+ "a": 0,
+ "k": [
+ 100,
+ 100
+ ]
+ },
+ "r": {
+ "a": 0,
+ "k": 0
+ },
+ "o": {
+ "a": 0,
+ "k": 100
+ }
+ }
+ ]
+ }
+ ],
+ "tt": 1,
+ "tp": 1
+ }
+],
+"meta": {
+ "g": "Glaxnimate 0.4.6-26-g7b05e75c"
+}
+}
+
diff --git a/schema/constants/matte-mode.json b/schema/constants/matte-mode.json
new file mode 100644
index 0000000..ae837c2
--- /dev/null
+++ b/schema/constants/matte-mode.json
@@ -0,0 +1,33 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "type": "integer",
+ "title": "Matte Mode",
+ "description": "How a layer should mask another layer",
+ "oneOf": [
+ {
+ "title": "Normal",
+ "description": "The layer is not used as a track matte",
+ "const": 0
+ },
+ {
+ "title": "Alpha",
+ "description": "The masked layer opacity is modulated by the track matte layer opacity",
+ "const": 1
+ },
+ {
+ "title": "Inverted Alpha",
+ "description": "The masked layer opacity is modulated by the inverted track matte layer opacity",
+ "const": 2
+ },
+ {
+ "title": "Luma",
+ "description": "The masked layer opacity is modulated by the track matte layer luminance",
+ "const": 3
+ },
+ {
+ "title": "Inverted Luma",
+ "description": "The masked layer opacity is modulated by the inverted track matte layer luminance",
+ "const": 4
+ }
+ ]
+}
diff --git a/schema/layers/visual-layer.json b/schema/layers/visual-layer.json
index 3f870d4..f7ce88a 100644
--- a/schema/layers/visual-layer.json
+++ b/schema/layers/visual-layer.json
@@ -21,6 +21,16 @@
"default": 0,
"description": "If 1, the layer will rotate itself to match its animated position path"
},
+ "tt": {
+ "title": "Matte Mode",
+ "$ref": "#/$defs/constants/matte-mode",
+ "description": "Defines the track matte mode for the layer"
+ },
+ "tp": {
+ "title": "Matte Parent",
+ "type": "integer",
+ "description": "Index of the layer used as matte, if omitted assume the layer above the current one"
+ },
"masksProperties": {
"title": "Masks",
"description": "Optional array of masks for the layer.",