Compiling#
The compiler itself. Source or IR in, Panel Core out.
Every entry point takes the same two optional keyword arguments – library and
metrics – so the character set and the font are both injectable, and neither is
read from the environment.
scenet.pipeline#
.. py:module:: scenet.pipeline
The compiler: source through IR to Panel Core.
Each stage is separable and independently testable, which is the point of having tiers at all. The frontend never computes a coordinate, the solver never touches artwork, and the emitter never makes a layout decision.
.. py:class:: CompileResult
- module:
scenet.pipeline
Bases: :py:class:
objectThe compiled panel, with the intermediate results kept for inspection.
Diagnostics – notably whether the camera had to retreat to fit the cast – are part of the result rather than log output, so tooling can surface them.
.. py:attribute:: CompileResult.core
- module:
scenet.pipeline
- type:
~scenet.core.PanelCore
.. py:attribute:: CompileResult.camera
- module:
scenet.pipeline
- type:
~scenet.solve.camera.CameraSolution
.. py:attribute:: CompileResult.placements
- module:
scenet.pipeline
- type:
tuple[~scenet.solve.staging.Placement, …]
.. py:attribute:: CompileResult.posed
- module:
scenet.pipeline
- type:
dict[str, ~scenet.assets.kinematics.ResolvedPuppet]
.. py:property:: CompileResult.notes
- module:
scenet.pipeline
- type:
tuple[str, …]
Human-readable diagnostics about how this panel was compiled.
- returns:
Zero or more sentences describing decisions the compiler had to make that were not literally what the source asked for – a camera that retreated to fit the cast, a balloon tail that had to bend around a face.
These are returned rather than logged so that tooling can put them in front of the person who wrote the panel. A camera that silently retreats leaves you with a panel that is quietly not the shot you asked for, which you would eventually notice and have no way to explain.
.. admonition:: Example
from scenet import compile_source crowded = compile_source( … “{panel: {size: [600.0, 400.0]}, camera: {shot: close_up},” … “ cast: {a: {reference: alice}, b: {reference: bob}},” … “ staging: [a left_of b]}” … ) any(“camera retreated” in note for note in crowded.notes) True
.. py:method:: CompileResult.init(core, camera, placements, posed)
- module:
scenet.pipeline
.. py:function:: compile_ir(panel, *, library=None, metrics=None)
- module:
scenet.pipeline
Compile validated IR into Panel Core.
- rtype:
- sphinx_autodoc_typehints_type:
\:py\:class\:\~scenet.pipeline.CompileResult``
.. py:function:: compile_source(text, *, source=None, library=None, metrics=None)
- module:
scenet.pipeline
Compile one panel from a source string.
The usual entry point, and the one to reach for first.
- type text:
- sphinx_autodoc_typehints_type:
\:py\:class\:\str``
- param text:
A single-panel document in the YAML surface syntax.
- type source:
- sphinx_autodoc_typehints_type:
\:py\:class\:\~pathlib.Path` | :py:obj:`None``
- param source:
Path the text came from, used only to prefix error messages. Pass it when you have one; the diagnostics are much more useful with it.
- type library:
- sphinx_autodoc_typehints_type:
\:py\:class\:\~scenet.assets.contract.PuppetLibrary` | :py:obj:`None``
- param library:
Characters to draw from. Defaults to the two shipped puppets.
- type metrics:
- sphinx_autodoc_typehints_type:
\:py\:class\:\~scenet.solve.text.FontMetrics` | :py:obj:`None``
- param metrics:
Font to measure lettering against. Defaults to the font that ships as a dependency of this package.
- rtype:
- sphinx_autodoc_typehints_type:
\:py\:class\:\~scenet.pipeline.CompileResult``
- returns:
The compiled panel, with the intermediate results kept for inspection.
- raises PanelSyntaxError:
The document is malformed or invalid.
- raises UnknownPuppetError:
A cast member references a character the library lacks.
- raises LayoutError:
The required constraints cannot all be satisfied.
- raises BalloonPlacementError:
A balloon has no legal position.
.. admonition:: Example
from scenet import compile_source, render result = compile_source( … “{cast: {alice: {reference: alice}}, script: [{say: {by: alice, text: Hello.}}]}” … ) len(result.core.balloons) 1 result.core.balloons[0].lines (‘Hello.’,) svg = render(result.core)
.. seealso::
- func:
compile_file <scenet.pipeline.compile_file>, to read from disk.- func:
compile_scene <scenet.pipeline.compile_scene>, for multi-panel documents.- func:
compile_document <scenet.pipeline.compile_document>, to dispatch on extension and accept any supported syntax.
.. py:function:: compile_file(path, *, library=None, metrics=None)
- module:
scenet.pipeline
Compile one panel from a file.
- type path:
- sphinx_autodoc_typehints_type:
\:py\:class\:\~pathlib.Path``
- param path:
A
*.panel.yamldocument.- type library:
- sphinx_autodoc_typehints_type:
\:py\:class\:\~scenet.assets.contract.PuppetLibrary` | :py:obj:`None``
- param library:
Characters to draw from. Defaults to the two shipped puppets.
- type metrics:
- sphinx_autodoc_typehints_type:
\:py\:class\:\~scenet.solve.text.FontMetrics` | :py:obj:`None``
- param metrics:
Font to measure lettering against.
- rtype:
- sphinx_autodoc_typehints_type:
\:py\:class\:\~scenet.pipeline.CompileResult``
- returns:
The compiled panel.
- raises OSError:
The file cannot be read.
- raises PanelSyntaxError:
The document is malformed or invalid. The path is included in the message.
.. py:function:: compile_scene(text, *, source=None, library=None, metrics=None)
- module:
scenet.pipeline
Compile every panel in a multi-panel document.
Each panel is compiled independently. A panel’s composition must not depend on what sits beside it, or the same source would compile differently in isolation – which would make panels non-reusable and golden tests meaningless.
- rtype:
- sphinx_autodoc_typehints_type:
\:py\:class\:\dict`\ \[:py:class:`str`, :py:class:`~scenet.pipeline.CompileResult`]`
.. py:function:: compile_scene_file(path, *, library=None, metrics=None)
- module:
scenet.pipeline
Compile every panel in a multi-panel file.
- type path:
- sphinx_autodoc_typehints_type:
\:py\:class\:\~pathlib.Path``
- param path:
A
*.scene.yamldocument. A single-panel document also works and comes back as one entry namedpanel.- type library:
- sphinx_autodoc_typehints_type:
\:py\:class\:\~scenet.assets.contract.PuppetLibrary` | :py:obj:`None``
- param library:
Characters to draw from. Defaults to the two shipped puppets.
- type metrics:
- sphinx_autodoc_typehints_type:
\:py\:class\:\~scenet.solve.text.FontMetrics` | :py:obj:`None``
- param metrics:
Font to measure lettering against.
- rtype:
- sphinx_autodoc_typehints_type:
\:py\:class\:\dict`\ \[:py:class:`str`, :py:class:`~scenet.pipeline.CompileResult`]`
- returns:
Panel name to compiled panel, in declaration order – which is reading order.
- raises OSError:
The file cannot be read.
- raises PanelSyntaxError:
A panel is malformed or invalid.
- raises CompositionError:
An
over:chain refers to a panel that does not exist, or forms a cycle.
.. py:function:: compile_document(path, *, library=None, metrics=None)
- module:
scenet.pipeline
Compile any supported document, choosing the frontend by extension.
- rtype:
- sphinx_autodoc_typehints_type:
\:py\:class\:\dict`\ \[:py:class:`str`, :py:class:`~scenet.pipeline.CompileResult`]`
scenet.compose#
.. py:module:: scenet.compose
Sparse override between panels.
Borrowed from OpenUSD’s composition arcs, and specifically from over: a panel names
a parent and states only what differs from it.
This matters more for comics than it might look. Consecutive panels in a scene are mostly identical – the same cast, the same staging, the same camera – with one thing changed. Restating all of it per panel is both tedious and a place for inconsistencies to creep in, which is exactly the continuity error comics readers notice.
panels:
p1:
camera: {shot: medium_shot}
cast:
alice: {reference: alice, at: left_third}
p2:
over: p1 # everything from p1...
camera: {shot: close_up} # ...except the framing
.. py:function:: merge(base, override)
- module:
scenet.compose
Deep-merge
overrideontobase, withoverridewinning.Mappings merge recursively so that changing one actor’s pose leaves the rest of the cast alone. Lists replace wholesale rather than concatenating:
scriptandstagingare ordered wholes, and appending to an inherited script would make it impossible to write a panel where somebody says less than in the panel before.- rtype:
- sphinx_autodoc_typehints_type:
\:py\:class\:\dict`\ \[:py:class:`str`, :py:data:`~typing.Any`]`
.. py:function:: resolve_overrides(panels)
- module:
scenet.compose
Resolve every panel’s
overchain into a self-contained document.Panels are resolved lazily with memoisation, so a chain is walked once however many panels hang off it, and declaration order does not matter – a panel may inherit from one declared later.
- rtype:
- sphinx_autodoc_typehints_type:
\:py\:class\:\dict`\ \[:py:class:`str`, :py:class:`dict`\ \[:py:class:`str`, :py:data:`~typing.Any`]]`