Editor · guide
Icons
Declaring what a type looks like with SVG path data, and the parser that made the attribute buildable.
Edit this page on GitHubDocuments
What it is#
SvgPath reads SVG path data — the d attribute — into a PathBuilder. SvgPathException says
where it could not.
EditorIconAttribute is what a type carries to say what it looks like: [EditorIcon("M12 2 2 22h20z")]
on a component, a behaviour or an asset class. TypeIcon and AssetIcon are the registrations it
becomes; EditorArt is the lookup every surface uses to find one.
What it is for#
Doc 36 § D6 spelled this attribute out and nothing implemented it, for a stated reason: there was no
SVG path parser, and turning M12 2L2 22h20z into segments was held to belong to an asset pipeline
rather than to every application at start-up. There is a parser now and it is about a hundred and
fifty lines, which does not survive the argument it was resting on.
What that cost was concrete. Every icon set on earth — Material, Lucide, Feather, Fluent, Bootstrap,
Phosphor — ships a 24-square grid and a string per glyph, and the only way into the engine was to
transcribe one into LineTo calls by hand. A plugin's component had no picture in the outliner, the
inspector header, the Add Component list or the Project panel, and could not be given one without
writing geometry in C#.
⚠ Every command in the grammar, including the two that are not lines or curves. H/V are what
a rectangle is written with and A — the elliptical arc — is what a rounded corner is written with;
a reader that dropped either would render about a third of Material Symbols as a squashed polygon.
The arc is F.6.5 of the specification, converted to centre parametrisation and emitted as cubics.
Using it#
Two forms, told apart by the extension, because both are what people actually have. Anything ending
in .svg is a file relative to the declaring plugin's own directory — and is not allowed to leave
it. Anything else is the path data itself, which needs no file and no IO.
Tint takes #rrggbb, or a --custom-property to follow a retheme, or nothing at all — and nothing
is usually right. A component's icon sits on a row of text and wants that row's colour, including
when the row is selected and the background has gone dark under it; a literal is for the file-type
glyphs in a grid, where being scannable by hue is the whole job.
⚠ A bad icon is a diagnostic and the plugin still loads. Every other declaration a plugin can
carry throws when it is the wrong shape, and that is right for them — a [CustomInspector] on the
wrong kind of class makes the plugin's own code unreachable. An icon is decoration, and refusing to
load a terrain module because somebody fat-fingered a path string would be the editor holding a
feature hostage over a picture.
Examples#
Path data inline, which is what an icon copied out of a set looks like:
[EditorIcon("M4 4h7v7H4zM13 4h7v7h-7zM13 13h7v7h-7zM4 13h7v7H4z", Tint = "#7cc4ff")]public struct Health { public float Current; public float Maximum;}A file a designer drew, beside the plugin:
[EditorIcon("Icons/stamina.svg")]public struct Stamina { public float Current;}The parser on its own, for anything that wants geometry rather than an icon:
using Vixen.Ui;public static class Triangle { /// <summary>Four steps: a move, two lines and the close.</summary> public static int Steps() => SvgPath.Parse("M12 2 2 22h20z").Count;}TryParse is the same thing without the throw, for reading a string somebody else wrote.
See also#
- Writing a plugin — the scan that reads the attribute, and the scope the
- registration lives in.
- Scene menus — one of the surfaces an
IconArtis drawn on. IconArt,IconPaint— what an icon is once it has been read: several paths, each with its own- paint, on a view box of its own.