Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More rendering #19

Merged
merged 8 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
mbasaglia marked this conversation as resolved.
Show resolved Hide resolved
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)