Skip to content

Commit

Permalink
More rendering (#19)
Browse files Browse the repository at this point in the history
* Transforms and coordiates

* Auto-link glossary items

* Add wording related to the render stack

* Fix build

* 3x3 Matrices

* Explain transforms a bit better

* Mention untransformed (0, 0)
  • Loading branch information
mbasaglia authored Aug 28, 2024
1 parent ce4f1ff commit 011aa98
Show file tree
Hide file tree
Showing 7 changed files with 229 additions and 3 deletions.
15 changes: 15 additions & 0 deletions docs/editing/extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,3 +304,18 @@ Example:
Output:

{lottie_gradient_alpha:0, 0.16, 0.18, 0.46, 0.5, 0.2, 0.31, 0.69, 1, 0.77, 0.85, 0.96, 0, 0.8, 0.5, 0.2, 1, 1}


### Glossary Terms

Glossary terms can be linked to using Mediawiki-style syntax:

Example:

```
[[local coordinates]] or [[local coordinates|coordinate system]]
```

Output:

[[local coordinates]] or [[local coordinates|coordinate system]]
20 changes: 20 additions & 0 deletions docs/specs/glossary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Glossary

local coordinates
: The local coordinate system is the coordinate system of the current
group or layer, with the X coordinate increasing towards the right
and the Y coordinate increasing towards the bottom.
Without any transforms, the point $(0, 0)$ corresponds with the top-left
corner of the viewport.
render stack
: A render stack is a list if rendering primitive to be drawn in inverse
stack order. A render stack can contain child stacks.
stacking order
: The order in which objects appear in the [[render stack]].
collected shapes
: When collecting shapes for a rendering operation, implementations MUST
traverse the [[render stack]] in reverse order.
All {link:shapes/shape:Shapes} encountered in the stack traversal MUST
be included, until the beginning of the stack is reached or a {link:shapes/modifier}
is encountered. If a {link:shapes/modifier} is found, it MUST be applied to
its own _collected shapes_ and the output added to the shape collection.
102 changes: 100 additions & 2 deletions docs/specs/helpers.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@

{schema_object:helpers/transform}


To make the anchor point properly line up with the center of location, `p` and `a` should have the same value.


This example allows you to tweak transform attributes and see how the shape changes.
{: .print-site-plugin-ignore }

Expand Down Expand Up @@ -46,6 +44,106 @@ The anchor point is highlighted with an orange dot.
</script>
</lottie-playground>

Transforms the parent's coordinate system.

When calculating the final transform, properties MUST be applied as follows:

1. Translate by $-a$
1. Scale by $\frac{s}{100}$
1. If $sk \neq 0$:
1. Rotate by $-sa$
1. Skew x by $\tan(-sk)$
1. Rotate by $sa$
1. Rotate by $-r$
1. Translate by $p$

Steps that have no effect MAY be skipped.

Assuming a transform matrix with the following layout, with the labels equivalent to the
[CSS matrix transform](https://drafts.csswg.org/css-transforms/#MatrixDefined):

$$
\begin{pmatrix}
a & b & 0 \\
c & d & 0 \\
e & f & 1
\end{pmatrix}
$$

The final transform is given by chaining transform matrices for each transform step:

$$
\begin{split}
&
\begin{pmatrix}
1 & 0 & 0 \\
0 & 1 & 0 \\
-a.x & -a.y & 1
\end{pmatrix}
\times
\begin{pmatrix}
\frac{s.x}{100} & 0 & 0 \\
0 & \frac{s.y}{100} & 0 \\
0 & 0 & 1
\end{pmatrix}
\times \\ \times &
\begin{pmatrix}
\cos(-sa) & \sin(-sa) & 0 \\
-\sin(-sa) & \cos(-sa)& 0 \\
0 & 0 & 1
\end{pmatrix}
\times
\begin{pmatrix}
1 & \tan(-sk) & 0 \\
0 & 1 & 0 \\
0 & 0 & 1
\end{pmatrix}
\times
\begin{pmatrix}
\cos(sa) & \sin(sa) & 0 \\
-\sin(sa) & \cos(sa) & 0 \\
0 & 0 & 1
\end{pmatrix}
\times \\ \times &
\begin{pmatrix}
\cos(-r) & \sin(-r) & 0 \\
-\sin(-r) & \cos(-r) & 0 \\
0 & 0 & 1
\end{pmatrix}
\times
\begin{pmatrix}
1 & 0 & 0 \\
0 & 1 & 0 \\
p.x & p.y & 1
\end{pmatrix}
\end{split}
$$

Note that if the transform matrix is transposed compared to the above:

$$
\begin{pmatrix}
a & c & e \\
b & d & f \\
0 & 0 & 1
\end{pmatrix}
$$

The operations need to be chained using right multiplication instead of left multiplication.

<h2 id="visual-object">Visual Object</h2>

{schema_string:helpers/visual-object/description}
Expand Down
19 changes: 19 additions & 0 deletions docs/specs/shapes.md
Original file line number Diff line number Diff line change
Expand Up @@ -371,19 +371,34 @@ $$

{schema_object:shapes/group}

A group defines a [[render stack]], elements within a group MUST be
rendered in reverse order (the first object in the list will appear on
top of elements further down).

1. Apply the transform
1. Render Styles and child groups in the transformed [[local coordinates|coordinate system]].

<h3 id="transform">Transform</h3>

{schema_string:shapes/transform/description}

{schema_object:shapes/transform}

Transform shapes MUST always be present in the group and they MUST be
the last item in the `it` array.

They modify the group's [[local coordinates|coordinate system]] the same way as Layer {link:helpers/transform}.


<h2 id="shape-style">Style</h2>

{schema_string:shapes/shape-style/description}

{schema_object:shapes/shape-style}

Shapes styles MUST apply their style to the [[collected shapes]] that
come before them in [[stacking order]].


<h3 id="fill">Fill</h3>

Expand Down Expand Up @@ -567,6 +582,10 @@ $$

{schema_string:shapes/modifier/description}

Modifiers replace shapes in the [[render stack]] by applying operating
on the bezier path of to the [[collected shapes]] that
come before it in [[stacking order]].


<h3 id="trim-path">Trim Path</h3>

Expand Down
3 changes: 3 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ markdown_extensions:
- attr_list
- lottie_markdown
- latex_markdown
- def_list
- toc_deflist
extra_css:
# - /lottie-spec/style/style.css
# - /lottie-spec/style/lottie-theme.css
Expand All @@ -28,6 +30,7 @@ nav:
- specs/assets.md
- specs/constants.md
- specs/helpers.md
- specs/glossary.md
#
- specs/schema.md
- validator/index.md
Expand Down
2 changes: 1 addition & 1 deletion tools/latex_markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def run(self, parent, blocks):
break
else:
code += last_block
last_block.pop(0)
last_block = blocks.pop(0)

for chunk in code.split("$$\n$$"):
element = latex2mathml.converter.convert_to_element(chunk, display="block")
Expand Down
71 changes: 71 additions & 0 deletions tools/toc_deflist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import xml.etree.ElementTree as etree

from markdown.treeprocessors import Treeprocessor
from markdown.inlinepatterns import InlineProcessor
from markdown.extensions import Extension
from markdown.extensions import toc

from lottie_markdown import get_url


class TocDefListTreeProcessor(Treeprocessor):
old_nest = toc.nest_toc_tokens

def __init__(self, md):
super().__init__(md)
self.extra_toc = []
# Patch toc.nest_toc_tokens to show glossary terms in the
# table of contents (Hack)
toc.nest_toc_tokens = self.patched_nest_toc_tokens

def patched_nest_toc_tokens(self, toc_list):
tl = TocDefListTreeProcessor.old_nest(toc_list + self.extra_toc)
self.extra_toc = []
return tl

def run(self, root):
self.extra_toc = []

term: etree.Element
for term in root.findall(".//dt"):
if "id" not in term.attrib:
text = toc.unescape(toc.stashedHTML2text(toc.get_name(term), self.md))
id = toc.slugify(text, "-")
term.attrib["id"] = id
link = etree.Element("a")
for child in term:
term.remove(child)
link.append(child)
link.text = term.text
term.text = ""
term.append(link)
link.attrib["href"] = "#" + id
self.extra_toc.append({
"level": 2,
"id": id,
"name": text
})


class GlossaryLink(InlineProcessor):
def __init__(self, md):
super().__init__(r'\[\[([^\]\|]+)(?:\|([^\]]+))?\]\]', md)

def handleMatch(self, match, data):
link = etree.Element("a")
title = match.group(1)
id = toc.slugify(title, "-")
link.attrib["href"] = get_url(self.md, "specs/glossary.md", id)
link.text = match.group(2) or title
return link, match.start(0), match.end(0)


class TocDefListExtension(Extension):
def extendMarkdown(self, md):
md.registerExtension(self)
md.treeprocessors.register(TocDefListTreeProcessor(md), "toc_deflist", 175)
md.inlinePatterns.register(GlossaryLink(md), "glossary_link", 175)


def makeExtension(**kwargs):
return TocDefListExtension(**kwargs)

0 comments on commit 011aa98

Please sign in to comment.