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:: expression
Which named expression 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 facing,
(dx, dy). Derived from the head’s rotation, and what balloon placement reads to keep out of a line of sight... attribute:: gaze_aim
Unit direction from the eyes to whoever this character is
looking_at, or None when they are looking at nobody. Separate fromgazebecause it is known only after every actor has been placed, and because balloon placement must go on reading the same vector it always has. This is what aims the pupils... attribute:: face_marks
The drawn face – brows, eyes, pupils, nose, mouth – as resolved numeric primitives. Empty when the puppet declares no features, or when the figure is too small for features to read as anything but a smudge.
.. attribute:: marks
Which emanata were asked for –
plewds,grawlixes, and so on... attribute:: emanata
The marks drawn around the character, as the same strokes and discs a face is made of. Empty when there are no marks, or when the figure is too small to have a face. Ids are numbered per mark:
plewd_0,plewd_1, ….. attribute:: emanata_zones
One polygon per mark, enclosing what it draws. Balloons and captions pay to cover these and are never forbidden to. Kept apart from
hullon purpose: the hull is what staging spaces characters by, and a character who starts sweating must not move... 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.expression
- module:
scenet.core
- type:
str
.. py:attribute:: CoreActor.gaze_aim
- module:
scenet.core
- type:
tuple[float, float] | None
.. py:attribute:: CoreActor.face_marks
- module:
scenet.core
- type:
tuple[~scenet.core.FaceStroke | ~scenet.core.FaceDisc, …]
.. py:attribute:: CoreActor.marks
- module:
scenet.core
- type:
tuple[~scenet.ir.Mark, …]
.. py:attribute:: CoreActor.emanata
- module:
scenet.core
- type:
tuple[~scenet.core.FaceStroke | ~scenet.core.FaceDisc, …]
.. py:attribute:: CoreActor.emanata_zones
- module:
scenet.core
- type:
tuple[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:: CoreAtmosphere
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelWhat the air is doing, resolved.
.. attribute:: time
When the panel happens. Recorded rather than re-derived, for the same reason
CoreCaption.italicis: the emitter must not be able to draw something the solver did not resolve... attribute:: weather
What is falling, if anything.
.. attribute:: tone
The atmosphere’s own value at this hour.
.. attribute:: veil
The noise layer – fog, or cloud for rain and snow.
.. attribute:: streaks
Rain, every streak at the same angle.
.. attribute:: flecks
Snow.
.. attribute:: streak_width
Stroke width for a streak, in panel units.
.. attribute:: fall_tone
What rain and snow are drawn in – ink over a bright sky, paper over a dark one. Resolved rather than left to the emitter, because which one reads is a fact about this panel.
.. py:attribute:: CoreAtmosphere.time
- module:
scenet.core
- type:
~scenet.ir.TimeOfDay
.. py:attribute:: CoreAtmosphere.weather
- module:
scenet.core
- type:
~scenet.ir.Weather
.. py:attribute:: CoreAtmosphere.tone
- module:
scenet.core
- type:
str
.. py:attribute:: CoreAtmosphere.veil
- module:
scenet.core
- type:
~scenet.core.CoreVeil | None
.. py:attribute:: CoreAtmosphere.streaks
- module:
scenet.core
- type:
tuple[~scenet.core.CoreStreak, …]
.. py:attribute:: CoreAtmosphere.flecks
- module:
scenet.core
- type:
tuple[~scenet.core.Disc, …]
.. py:attribute:: CoreAtmosphere.streak_width
- module:
scenet.core
- type:
float
.. py:attribute:: CoreAtmosphere.fall_tone
- module:
scenet.core
- type:
str
.. py:class:: CoreBackdrop
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelWhere the panel is, resolved: masses, tones, and the air.
.. attribute:: horizon
Where the ground meets what is behind it, in panel units.
.. attribute:: seed
What every silhouette in here was generated from. Kept so that a Core document explains itself: two panels with the same masses and different skylines differ here, and here is where to look.
.. attribute:: masses
The tonal masses, back to front.
.. attribute:: atmosphere
The air, or None when the weather is clear.
Optional on :class:
PanelCore <scenet.core.PanelCore>, so every document written before this existed is still a valid one – which is why adding it did not need aformat_versionbump, the same argument captions made... py:attribute:: CoreBackdrop.horizon
- module:
scenet.core
- type:
float
.. py:attribute:: CoreBackdrop.seed
- module:
scenet.core
- type:
int
.. py:attribute:: CoreBackdrop.masses
- module:
scenet.core
- type:
tuple[~scenet.core.CoreMass, …]
.. py:attribute:: CoreBackdrop.atmosphere
- module:
scenet.core
- type:
~scenet.core.CoreAtmosphere | None
.. 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:: CoreCaption
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelOne caption box, placed and with its lettering already broken into lines.
.. attribute:: id
Stable identifier,
c0,c1, … in the order the captions appear... attribute:: order
Position in the panel’s reading order. Captions and balloons share one sequence, so a caption written between two lines of dialogue takes the number between theirs.
.. attribute:: kind
What the box is doing, which is what decides how it is set.
.. attribute:: box
Where it sits.
.. attribute:: lines
The resolved line breaking, quotation marks included. A
spokencaption’s quotes are part of the text by the time it reaches here, because marks added after measurement would not fit the box drawn for them... attribute:: font_size
Type size in panel units.
.. attribute:: line_height
Baseline-to-baseline distance in panel units.
.. attribute:: italic
Whether the lettering is set in the italic face. Recorded rather than re-derived from
kindso the emitter cannot draw the box in a face the solver did not measure it in... attribute:: fill
The value the box is filled with, resolved from the declared tone.
.. attribute:: ink
The value the lettering is drawn in. Chosen against
fillby contrast, so a dark box is lettered in paper – reversed type. Resolved rather than left to the emitter for the same reasonitalicis, and the same reason- attr:
CoreAtmosphere.fall_tone <scenet.core.CoreAtmosphere>is: which mark reads is a fact about the panel.
.. attribute:: speaker
Who is talking, for a
spokencaption. Not an actor id: the speaker is off panel, so this resolves to nobody inactors.There is no tail. That is the difference that makes this its own type rather than a fifth :class:
BalloonKind <scenet.ir.BalloonKind>.fillandinkare defaulted to the white and the near-black every caption has had since captions shipped, so a Core document written before tones existed is still a valid one – which is why adding them needed noformat_versionbump... py:attribute:: CoreCaption.id
- module:
scenet.core
- type:
str
.. py:attribute:: CoreCaption.order
- module:
scenet.core
- type:
int
.. py:attribute:: CoreCaption.kind
- module:
scenet.core
- type:
~scenet.ir.CaptionKind
.. py:attribute:: CoreCaption.box
- module:
scenet.core
- type:
~scenet.core.Box
.. py:attribute:: CoreCaption.lines
- module:
scenet.core
- type:
tuple[str, …]
.. py:attribute:: CoreCaption.font_size
- module:
scenet.core
- type:
float
.. py:attribute:: CoreCaption.line_height
- module:
scenet.core
- type:
float
.. py:attribute:: CoreCaption.italic
- module:
scenet.core
- type:
bool
.. py:attribute:: CoreCaption.fill
- module:
scenet.core
- type:
str
.. py:attribute:: CoreCaption.ink
- module:
scenet.core
- type:
str
.. py:attribute:: CoreCaption.speaker
- module:
scenet.core
- type:
str | None
.. py:class:: CoreMass
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelOne tonal mass of the backdrop, resolved to a numeric polygon.
The same discipline as
capsules,blobsandface_marks: everything the emitter needs is a number by the time it gets here, so drawing a backdrop involves no layout decision at all... attribute:: id
Stable identifier,
m0,m1, … back to front... attribute:: kind
What the mass is made of. Carried so a Core document stays readable – it is not consulted when drawing, since the tone is already resolved.
.. attribute:: plane
How far back it sits.
.. attribute:: depth
Painter’s order, shared with the actors. Backdrop planes are negative; a foreground mass sits above the frontmost actor.
.. attribute:: tone
The
#rrggbbfill, already chosen from the value ladder... attribute:: polygon
The silhouette, in panel coordinates.
.. py:attribute:: CoreMass.id
- module:
scenet.core
- type:
str
.. py:attribute:: CoreMass.kind
- module:
scenet.core
- type:
~scenet.ir.MassKind
.. py:attribute:: CoreMass.plane
- module:
scenet.core
- type:
~scenet.ir.Plane
.. py:attribute:: CoreMass.depth
- module:
scenet.core
- type:
int
.. py:attribute:: CoreMass.tone
- module:
scenet.core
- type:
str
.. py:attribute:: CoreMass.polygon
- module:
scenet.core
- type:
tuple[tuple[float, float], …]
.. py:class:: CoreStreak
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelOne streak of falling rain.
The width is on :class:
CoreAtmosphere <scenet.core.CoreAtmosphere>rather than here: every streak in a panel shares it, and repeating it per streak would make the file longer without making it say anything more... py:attribute:: CoreStreak.start
- module:
scenet.core
- type:
tuple[float, float]
.. py:attribute:: CoreStreak.end
- module:
scenet.core
- type:
tuple[float, float]
.. py:class:: CoreVeil
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelThe atmospheric noise layer, as parameters rather than as pixels.
SVG has Perlin noise built in through
feTurbulence, and the specification includes reference code, so a fixedseedis reproducible by definition: the emitted text is byte-identical. Browsers agree only approximately on what to paint from it, which is fine and is exactly why the determinism contract is on the SVG text and has never been on pixels... attribute:: tone
The
#rrggbbthe veil is tinted... attribute:: opacity
How much of it lands,
0 .. 1... attribute:: frequency
baseFrequency, per panel unit... attribute:: octaves
numOctaves... attribute:: seed
seed, derived from the declared content and the panel size... py:attribute:: CoreVeil.tone
- module:
scenet.core
- type:
str
.. py:attribute:: CoreVeil.opacity
- module:
scenet.core
- type:
float
.. py:attribute:: CoreVeil.frequency
- module:
scenet.core
- type:
float
.. py:attribute:: CoreVeil.octaves
- module:
scenet.core
- type:
int
.. py:attribute:: CoreVeil.seed
- module:
scenet.core
- type:
int
.. py:class:: Disc
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelA circle, as stored in a Core document.
Usually a face exclusion zone – the region no balloon may cover. Also a fleck of falling snow, which is the same shape and wants the same rounding.
.. 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:: FaceDisc
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelA round mark on a face – an eye, or the pupil inside it.
.. attribute:: mark
Always
disc... attribute:: id
Which feature this draws.
.. attribute:: centre
(x, y)of the centre... attribute:: radius
Radius in panel units.
.. attribute:: filled
Filled marks are pupils; outlined ones are the eyes around them.
.. attribute:: width
Outline width in panel units, ignored when
filled... py:attribute:: FaceDisc.mark
- module:
scenet.core
- type:
~typing.Literal[‘disc’]
.. py:attribute:: FaceDisc.id
- module:
scenet.core
- type:
str
.. py:attribute:: FaceDisc.centre
- module:
scenet.core
- type:
tuple[float, float]
.. py:attribute:: FaceDisc.radius
- module:
scenet.core
- type:
float
.. py:attribute:: FaceDisc.filled
- module:
scenet.core
- type:
bool
.. py:attribute:: FaceDisc.width
- module:
scenet.core
- type:
float
.. py:data:: FaceMark
- module:
scenet.core
- value:
scenet.core.FaceStroke | scenet.core.FaceDisc
One mark on a drawn face, or of the emanata drawn around it – they are made of the same two primitives. Tagged by a defaulted literal rather than a pydantic discriminator, for the same reason
ScriptEventis: a discriminator would require the tag in every hand-written document.
.. py:class:: FaceStroke
- module:
scenet.core
Bases: :py:class:
~scenet.core.CoreModelOne line of a drawn face, already sampled into straight segments.
Curves are sampled during compilation rather than emitted as Bezier control points, so that everything an expression does is a number here. A face can then be read, diffed and hand-adjusted exactly like the rest of this tier, and the emitter has nothing left to decide.
.. attribute:: mark
Always
stroke. What distinguishes this from aFaceDisc... attribute:: id
Which feature this draws –
brow_l,mouth, and so on... attribute:: points
The polyline, in panel coordinates.
.. attribute:: width
Stroke width in panel units.
.. attribute:: closed
Whether the last point joins back to the first, which is what makes an open mouth a shape rather than a stray arc.
.. py:attribute:: FaceStroke.mark
- module:
scenet.core
- type:
~typing.Literal[‘stroke’]
.. py:attribute:: FaceStroke.id
- module:
scenet.core
- type:
str
.. py:attribute:: FaceStroke.points
- module:
scenet.core
- type:
tuple[tuple[float, float], …]
.. py:attribute:: FaceStroke.width
- module:
scenet.core
- type:
float
.. py:attribute:: FaceStroke.closed
- module:
scenet.core
- type:
bool
.. 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.
.. attribute:: captions
Resolved caption boxes, in reading order. Balloons and captions share one
ordersequence, since the reader takes them in one sequence... attribute:: backdrop
Where the panel is, or None when it says nothing about that – which is every panel written before the setting layer existed.
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:attribute:: PanelCore.captions
- module:
scenet.core
- type:
tuple[~scenet.core.CoreCaption, …]
.. py:attribute:: PanelCore.backdrop
- module:
scenet.core
- type:
~scenet.core.CoreBackdrop | None
.. 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`]`