Panel Core#
The resolved intermediate format: fully numeric, still named, and a real file format rather than a private data structure.
scenet.core#
.. py:module:: scenet.core
Panel Core: the resolved intermediate format.
Every position is absolute and numeric, but identifiers survive – which is what separates this from SVG. A Core document can be read, diffed, hand-adjusted and re-emitted.
Golden-file tests target this tier rather than the SVG, because it changes only when layout genuinely changes. Diffing SVG text is brittle: a reordered attribute or a different path-rounding convention produces a huge diff that means nothing.
.. py:class:: Blob
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelA rounded mass – a head, a hand – drawn as a filled circle.
.. attribute:: centre
(x, y)of the centre... attribute:: radius
Radius in panel units.
.. py:attribute:: Blob.centre
- module:
scenet.core
- type:
tuple[float, float]
.. py:attribute:: Blob.radius
- module:
scenet.core
- type:
float
.. py:class:: Box
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelA rectangle, as stored in a Core document.
The serialisable twin of :class:
BBox <scenet.geom.BBox>. The geometry code works inBBox; this is what gets written to JSON, with every value already rounded so the file is byte-identical across platforms... attribute:: x
Left edge.
.. attribute:: y
Top edge.
.. attribute:: width
Extent rightward.
.. attribute:: height
Extent downward.
.. py:attribute:: Box.x
- module:
scenet.core
- type:
float
.. py:attribute:: Box.y
- module:
scenet.core
- type:
float
.. py:attribute:: Box.width
- module:
scenet.core
- type:
float
.. py:attribute:: Box.height
- module:
scenet.core
- type:
float
.. py:property:: Box.right
- module:
scenet.core
- type:
float
The right edge,
x + width.
.. py:property:: Box.bottom
- module:
scenet.core
- type:
float
The bottom edge,
y + height.
.. py:method:: Box.of(bbox)
- module:
scenet.core
- classmethod:
Build a `Box` from a geometry `BBox`, rounding for emission. :type bbox: :sphinx_autodoc_typehints_type:`\:py\:class\:\`\~scenet.geom.BBox\`` :param bbox: The box to convert. :rtype: :sphinx_autodoc_typehints_type:`\:py\:class\:\`\~typing.Self\`` :returns: The serialisable equivalent, with all four values rounded.
.. py:method:: Box.as_bbox() :module: scenet.core
Convert back to a geometry `BBox` for further computation. :rtype: :sphinx_autodoc_typehints_type:`\:py\:class\:\`\~scenet.geom.BBox\``
.. py:class:: Capsule
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelA limb segment, as a thick line with rounded ends.
.. py:attribute:: Capsule.start
- module:
scenet.core
- type:
tuple[float, float]
.. py:attribute:: Capsule.end
- module:
scenet.core
- type:
tuple[float, float]
.. py:attribute:: Capsule.width
- module:
scenet.core
- type:
float
.. py:class:: CoreActor
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelOne character, fully resolved: placed, posed, scaled and measured.
This is the geometric contract in its final form. Everything the emitter needs to draw the figure, and everything the balloon placer needed to avoid it, with no reference to artwork of any kind.
.. attribute:: id
The actor id from the panel source.
.. attribute:: reference
Which puppet was used. Two actors may share one.
.. attribute:: pose
Which named pose was applied.
.. attribute:: transform
Where the root joint landed, and the scale and mirroring applied.
.. attribute:: anchors
Named attachment points –
mouth,eyes, and whatever else the puppet declared – already in panel coordinates... attribute:: face_exclusion
The disc no balloon may overlap.
.. attribute:: gaze
Unit direction the character is looking,
(dx, dy)... attribute:: hull
Convex silhouette, used for the soft occlusion cost.
.. attribute:: capsules
Limb segments, as thick rounded lines.
.. attribute:: blobs
Rounded masses such as the head.
.. attribute:: depth
Painter’s order. Lower is drawn first, so higher sits in front.
.. py:attribute:: CoreActor.id
- module:
scenet.core
- type:
str
.. py:attribute:: CoreActor.reference
- module:
scenet.core
- type:
str
.. py:attribute:: CoreActor.pose
- module:
scenet.core
- type:
str
.. py:attribute:: CoreActor.transform
- module:
scenet.core
- type:
~scenet.core.Transform
.. py:attribute:: CoreActor.anchors
- module:
scenet.core
- type:
dict[str, tuple[float, float]]
.. py:attribute:: CoreActor.face_exclusion
- module:
scenet.core
- type:
~scenet.core.Disc
.. py:attribute:: CoreActor.gaze
- module:
scenet.core
- type:
tuple[float, float]
.. py:attribute:: CoreActor.hull
- module:
scenet.core
- type:
tuple[tuple[float, float], …]
.. py:attribute:: CoreActor.capsules
- module:
scenet.core
- type:
tuple[~scenet.core.Capsule, …]
.. py:attribute:: CoreActor.blobs
- module:
scenet.core
- type:
tuple[~scenet.core.Blob, …]
.. py:attribute:: CoreActor.depth
- module:
scenet.core
- type:
int
.. py:property:: CoreActor.bounds
- module:
scenet.core
- type:
~scenet.geom.BBox
Axis-aligned bounds of the silhouette.
.. py:class:: CoreBalloon
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelOne balloon, placed and with its lettering already broken into lines.
.. attribute:: id
Stable identifier,
b0,b1, … in script order... attribute:: speaker
Actor id of whoever is talking.
.. attribute:: order
Position in reading order, counting from zero.
.. attribute:: kind
Which sort of balloon to draw.
.. attribute:: box
Where it sits.
.. attribute:: lines
The resolved line breaking, not the source string.
.. attribute:: font_size
Type size in panel units.
.. attribute:: line_height
Baseline-to-baseline distance in panel units.
.. attribute:: tail
The pointer to the speaker’s mouth.
Storing broken lines rather than the original string is deliberate. Wrapping is decided during compilation against real font metrics; if the emitter re-measured, it could disagree with the solver about how wide the balloon needed to be, and the text would overflow the shape drawn for it.
.. py:attribute:: CoreBalloon.id
- module:
scenet.core
- type:
str
.. py:attribute:: CoreBalloon.speaker
- module:
scenet.core
- type:
str
.. py:attribute:: CoreBalloon.order
- module:
scenet.core
- type:
int
.. py:attribute:: CoreBalloon.kind
- module:
scenet.core
- type:
~scenet.ir.BalloonKind
.. py:attribute:: CoreBalloon.box
- module:
scenet.core
- type:
~scenet.core.Box
.. py:attribute:: CoreBalloon.lines
- module:
scenet.core
- type:
tuple[str, …]
.. py:attribute:: CoreBalloon.font_size
- module:
scenet.core
- type:
float
.. py:attribute:: CoreBalloon.line_height
- module:
scenet.core
- type:
float
.. py:attribute:: CoreBalloon.tail
- module:
scenet.core
- type:
~scenet.core.Tail
.. py:class:: Disc
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelA circle, as stored in a Core document.
In practice always a face exclusion zone – the region no balloon may cover.
.. attribute:: cx
Centre x.
.. attribute:: cy
Centre y.
.. attribute:: r
Radius.
.. py:attribute:: Disc.cx
- module:
scenet.core
- type:
float
.. py:attribute:: Disc.cy
- module:
scenet.core
- type:
float
.. py:attribute:: Disc.r
- module:
scenet.core
- type:
float
.. py:method:: Disc.of(circle)
- module:
scenet.core
- classmethod:
Build a `Disc` from a geometry `Circle`, rounding for emission. :type circle: :sphinx_autodoc_typehints_type:`\:py\:class\:\`\~scenet.geom.Circle\`` :param circle: The circle to convert. :rtype: :sphinx_autodoc_typehints_type:`\:py\:class\:\`\~typing.Self\`` :returns: The serialisable equivalent.
.. py:method:: Disc.as_circle() :module: scenet.core
Convert back to a geometry `Circle` for further computation. :rtype: :sphinx_autodoc_typehints_type:`\:py\:class\:\`\~scenet.geom.Circle\``
.. py:class:: PanelCore
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelA fully resolved panel: numeric, named, and ready to emit.
The middle tier, and the architectural idea of the project. Every position here is absolute and final, but identifiers survive – which is exactly what separates this from SVG. You can read a Core document, see that
alicesits at x=280 with her balloon top-left of her head, change one number, and emit it again.The approach is borrowed from Vega-Lite, which compiles a high-level grammar into a lower-level one before emitting anything drawable.
.. attribute:: format_version
Bumped when the shape of this document changes incompatibly.
.. attribute:: width
Panel width in panel units.
.. attribute:: height
Panel height in panel units.
.. attribute:: actors
Resolved characters, in declaration order.
.. attribute:: balloons
Resolved balloons, in reading order.
Golden-file tests target this tier rather than the SVG, because it changes only when the layout genuinely changes. Diffing SVG text is brittle – a reordered attribute or a different path-rounding convention produces an enormous diff that means nothing.
.. admonition:: Example
from scenet import compile_source core = compile_source(“{cast: {a: {reference: alice}}}”).core core.width, core.height (1000.0, 1000.0) core.actor(“a”).reference ‘alice’ core.to_json().splitlines()[0] ‘{’
.. py:attribute:: PanelCore.format_version
- module:
scenet.core
- type:
int
.. py:attribute:: PanelCore.width
- module:
scenet.core
- type:
float
.. py:attribute:: PanelCore.height
- module:
scenet.core
- type:
float
.. py:attribute:: PanelCore.actors
- module:
scenet.core
- type:
tuple[~scenet.core.CoreActor, …]
.. py:attribute:: PanelCore.balloons
- module:
scenet.core
- type:
tuple[~scenet.core.CoreBalloon, …]
.. py:property:: PanelCore.bounds
- module:
scenet.core
- type:
~scenet.geom.BBox
The panel rectangle, origin at
(0, 0).
.. py:method:: PanelCore.actor(actor_id)
- module:
scenet.core
Look up one actor by id.
- type actor_id:
- sphinx_autodoc_typehints_type:
\:py\:class\:\str``
- param actor_id:
The id used in the panel source.
- rtype:
- sphinx_autodoc_typehints_type:
\:py\:class\:\~scenet.core.CoreActor``
- returns:
That actor.
- raises KeyError:
No actor in this panel has that id.
.. py:method:: PanelCore.to_json()
- module:
scenet.core
Serialise deterministically.
Keys are sorted and floats already rounded at construction, so the same input yields byte-identical output on any platform. A trailing newline keeps the file well-formed for line-oriented tools like git diff.
- rtype:
- sphinx_autodoc_typehints_type:
\:py\:class\:\str``
.. py:method:: PanelCore.from_json(text)
- module:
scenet.core
- classmethod:
Read a Core document back in. The inverse of :meth:`to_json <scenet.core.PanelCore.to_json>`, and the reason Panel Core is a real format rather than a private data structure: a layout can be exported, adjusted by hand or by another tool, and read back for emission. :type text: :sphinx_autodoc_typehints_type:`\:py\:class\:\`str\`` :param text: A Core document. :rtype: :sphinx_autodoc_typehints_type:`\:py\:class\:\`\~typing.Self\`` :returns: The parsed panel. :raises pydantic.ValidationError: The document is not a valid Core panel. :raises json.JSONDecodeError: The text is not JSON at all.
.. py:class:: Tail
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelThe pointer from a balloon to its speaker’s mouth.
controlis present only when the straight route was obstructed and the tail had to bend, which keeps the common case honest about being a simple straight line... py:attribute:: Tail.start
- module:
scenet.core
- type:
tuple[float, float]
.. py:attribute:: Tail.end
- module:
scenet.core
- type:
tuple[float, float]
.. py:attribute:: Tail.control
- module:
scenet.core
- type:
tuple[float, float] | None
.. py:attribute:: Tail.width
- module:
scenet.core
- type:
float
.. py:property:: Tail.is_curved
- module:
scenet.core
- type:
bool
Whether this tail had to bend around an obstacle.
.. py:class:: Transform
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelWhere a puppet’s root joint lands, and how it is scaled and mirrored.
.. py:attribute:: Transform.x
- module:
scenet.core
- type:
float
.. py:attribute:: Transform.y
- module:
scenet.core
- type:
float
.. py:attribute:: Transform.scale
- module:
scenet.core
- type:
float
.. py:attribute:: Transform.mirrored
- module:
scenet.core
- type:
bool
.. py:function:: point_pair(point)
- module:
scenet.core
Convert a point to the rounded
(x, y)pair a Core document stores.- rtype:
- sphinx_autodoc_typehints_type:
\:py\:class\:\tuple`\ \[:py:class:`float`, :py:class:`float`]`
.. py:function:: round_pairs(points)
- module:
scenet.core
Convert a sequence of points – a hull, typically – to rounded pairs.
- rtype:
- sphinx_autodoc_typehints_type:
\:py\:class\:\tuple`\ \[:py:class:`tuple`\ \[:py:class:`float`, :py:class:`float`], :py:data:`…<Ellipsis>`]`
.. py:function:: vector_pair(vector)
- module:
scenet.core
Convert a vector to the rounded
(dx, dy)pair a Core document stores.- rtype:
- sphinx_autodoc_typehints_type:
\:py\:class\:\tuple`\ \[:py:class:`float`, :py:class:`float`]`