SVG Matrices & Layouts
How nittygrid maps animations onto custom-shaped displays drawn as SVG, how to import a background image in Matrix Setup, and how SVGs are kept safe offline.
Real displays are rarely a neat rectangle. A car light bar curves, a wearable follows the body, a sign has gaps. nittygrid handles this by splitting the problem in two:
- Where animations draw: a plain grid of cells, like a tiny screen.
- How your display looks: an SVG file (a vector drawing) where each shape is one physical LED.
Each frame, nittygrid reads the color of a grid cell and paints it onto the matching SVG shape. Effects never need to know your display's shape.
Add a background image
In Matrix setup you can import a photo or render of your product (PNG, JPG, WebP) behind your LEDs. This works for both regular grids and SVG layouts.
- Align by dragging. Move and resize the LED overlay on the photo until it matches the real LEDs. Grids can be stretched freely (hold Shift on a corner to keep proportions). SVG layouts always keep their aspect ratio.
- Image scale vs. Preview zoom. Image scale changes how big the photo is in the saved result. Preview zoom (or trackpad pinch) only magnifies your view while aligning.
- It is saved with your work. The image and alignment are stored in matrix presets and in
.ngprojfiles. An.mp4export can include it too (Include preview image).
How to prepare an SVG
SVG can contain almost anything. For LED layouts, keep it simple.
- Draw one shape per LED
Shapes inside
<defs>,<clipPath>,<mask>, or<symbol>are ignored. Standalone<use>copies are rejected, so expand them into real shapes first. - Optionally label rows and columns
Add
id="px-ROW-COL"(ordata-rowanddata-col) with numbers that start at0in the top-left:<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 40"> <rect id="px-0-0" data-led-id="px-0-0" data-row="0" data-col="0" x="4" y="4" width="28" height="12" rx="2" /> <rect id="px-0-1" data-led-id="px-0-1" data-row="0" data-col="1" x="44" y="4" width="28" height="12" rx="2" /> <rect id="px-0-2" data-led-id="px-0-2" data-row="0" data-col="2" x="84" y="4" width="28" height="12" rx="2" /> </svg> - Or upload it without labels
nittygrid sorts shapes by their center points: ascending
y, then ascendingx. It assigns the resulting list to consecutive grid cells. This is a spatial fallback, not a wiring order; add row and column labels when you need a specific mapping. - Split cells (optional)
If one cell holds two separately wired LEDs, such as an upper and a lower triangle, mark them
data-part="0"anddata-part="1". They stay two separate LEDs in exports.
Safety and cleanup
SVG files are XML and could in theory contain scripts or links to the internet. nittygrid cleans every SVG you upload, restore, or import from a project file.
- No code runs. Scripts and animations are removed. The layout is shown inside an isolated shadow root and never parsed as HTML, so its styles cannot change the app.
- Fully offline. External images, fonts, and stylesheets are removed, so the layout looks the same years from now.
- Common editor exports just work. Standard
DOCTYPElines, comments, and missingxmlnsare fixed, and wrapper tags like Illustrator's<switch>are unwrapped.
Technical reference: the exact rules
Generated from the app's own SVG import code, so it always matches what nittygrid does. This is for technicians and AI agents.
| Rule Category | Specification |
|---|---|
Eligible LED geometry (SHAPE_TAGS) | <path>, <circle>, <rect>, <ellipse>, <polygon>, <polyline>, <line> |
| Preserved geometry attributes | d, points, x, y, width, height, cx, cy, r, rx, ry, x1, y1, x2, y2, transform, fill-rule, clip-rule, pathLength |
Excluded definition contexts & <use> policy | Shapes inside <defs>, <clipPath>, <mask>, <marker>, <pattern>, or <symbol> are presentation definitions, never LEDs. Standalone <use> instances are rejected—expand instances into independent shapes before importing. |
| Canonical LED metadata & group inheritance | data-led-id (stable portable LED identity), id="px-ROW-COL", data-row="ROW", data-col="COL", optional data-part="PART" (0-based top-left origin). Logical addresses on ancestor <g> or <svg> elements are inherited during normalization; unusable or duplicate metadata attributes are stripped cleanly on import instead of rejecting the file. |
| Untagged sampling order & identity | Without sampling addresses, LEDs are sorted by center cy, then cx and sampled from consecutive grid cells. Addressed layouts sort by sampling y, then x. When a row/col/part address lands on a cell another LED already uses, explicit data-x/data-y addresses keep their cell and the other LED moves to a spare row below the grid. data-parts-per-cell counts only as a positive whole number. IDs remain paired with their source shapes; SVG element order is not a hardware wiring order. |
| Accepted import aliases & editor cleanup | id="led-rNN-cNNN" (automatically flipped from bottom-left to top-left origin on import). Standard DOCTYPEs, XML comments, and CDATA markers are stripped; missing SVG namespaces are added; unsupported containers like Illustrator <switch> are unwrapped. |
| Shadow DOM isolation & removed active elements | Layouts render inside an isolated shadow root imported from the XML parse (never re-parsed as HTML, and SVG <style> rules cannot restyle the app). Strips <script>, <foreignObject>, <iframe>, <embed>, <object>, <audio>, <video>, SMIL animation tags, <handler>, and <listener>. |
| Offline link, raster & buffer budgets | External href / xlink:href / CSS url(...) and @import rules are stripped. Only local #... fragments and header-verified data:image/(png|jpeg|gif|webp);base64 rasters (≤ 4 MiB, ≤ 4 MP, ≤ 4096 px/side) are allowed. Sampling addresses are capped at a 2048 × 2048 render buffer (≤ 8 MiB UTF-8 SVG for portable export). |
What each LED stores
Each LED in an SVG layout keeps four separate pieces of information:
- Identity (
data-led-id): its permanent, unique name across saves and.ngrender.json/.ngrender.zipexports. - Logical address (
row,col,part): optional 0-based grid position, starting top-left. - Sample position (
x,y): the integer slot in theW × Hgrid that the renderer reads its color from. - Shape (
tag,attrs,cx,cy): the actual outline and center point inside the SVGviewBox.
LED identities are assigned before sorting and remain paired with their original shapes. For addressed layouts, the pixel list is sorted by sampling y, then x; for unaddressed layouts, it is sorted by center cy, then cx. Exported frame colors follow the explicit LED list in the animation JSON. Consumers should use that list, not the SVG element order, to interpret the frames.