Notes for theme-able SVGs with nanoSvg

I had an idea for how to do theming with nanoSVG, and spent some time doing basic research and writing it up. Here’s the detailed notes: SVG Theme Notes

If there is interest from others, I might try an implementation and make it available in a reusable form.

With this scheme, you operate on a loaded SVG, and apply a stylesheet written in JSON that matches SVG elements by id to change colors. Very simple and lean. The SVG remains editable in Inkscape. There would be helpers to add a Theme menu with options for each of the themes you define.

4 Likes

I’d personally be very interested in this as I’m (slowly) building two modues and have been thinking of themeing options. The first being a v2 implementation of an old v0.5/6 plugin that would have different themes. The other is an alternate firmware port of a well known module that would have completely different panels with maybe some additional colour options for each of the panels.

The original Rack version of Surge did similar to what you’re proposing but with an XML stylesheet.

<surge-rack-skin name="Classic">
  <colors>
    <color name="panelBackground" hex="#CDCED4"/>
    <color name="panelBackgroundOutline" hex="#ADB0B7"/>
    <color name="panelFooter" hex="#FF9000"/>
    <color name="panelFooterOutline" hex="#E37008"/>
    <color name="panelFooterSeparator" hex="#123463"/>
    <color name="panelLabel" hex="#123463"/>
    <color name="panelLabelRule" hex="#123463"/>
    <color name="panelTitle" hex="#123463"/>
    <color name="panelSeparator" hex="#ADB0B7"/>

[snipped]

</colors>
  <assets>
    <asset name="surgeKnobBG" path="res/vectors/surgeKnobRotateBG.svg"/>
    <asset name="surgeKnobOverlay" path="res/vectors/surgeKnobOverlay.svg"/>
    <asset name="surgeKnobFG" path="res/vectors/surgeKnobRotateFG.svg"/>a

    <asset name="surgeKnobRoosterBG" path="res/vectors/surgeKnobRoosterBG.svg"/>
    <asset name="surgeKnobRoosterFG" path="res/vectors/surgeKnobRoosterFG.svg"/>a
  </assets>
</surge-rack-skin>

new version does basically the same just i don’t serialize the color choices to xml but keep them in code.

I definitely used to change SVG colors though and it worked great for those assets. Basically you can just traverse the svg object and whack whatever color you find in the tree. With the new version we really minimized our SVG usage though. Just a few knobs and background panels and the rest we paint into FrameBuffers using a frame buffer lambda class

1 Like

That’s the idea. I’ve got a start on the implementation, so I’ll update when I have an MVP ready.

cool here’s the old surge svg code if that helps surge-rack/src/SurgeWidgets.hpp at 5fdec2a4521b7f85d054bbcf72cef17537da3f8b · surge-synthesizer/surge-rack · GitHub

I’ve finished the implementation, documentation, and a Demo module for this proposal.

See Paul-Dempsey/svg_theme: Lean in-memory SVG theming for VCV Rack plugins. (github.com).

I think it’s pretty much ready for production, but I’m sure that thought is a brief bit of hubris that won’t survive first contact with real developers. If you run into a problem, I’m listening, and if you find a bug, please open an issue on GitHub.

I ended up using two header files. One for Rack-independent nanosvg theming, and another for helpers dependent on VCV Rack.

The Demo is a complete working plugin implementing a single Blank panel, backed by an SVG using standard Rack SvgPanel class. The demo also includes an example of a theme-able widget. In this case, a theme-able version of the standard Rack screws. Applying the Dark theme gives you the look of the Rack ScrewBlack, and the Light theme is the look of the Rack ScrewSilver (with one Screw.svg).

The demo shows how to theme a stock widget, and also how to implement theme-able widgets that can all be updated to a new theme with one line of code.

The Theme menu in the module is created by calling another helper that does all the work for you. You just implement a trivially-implementable interface on your module widget.

4 Likes