Skip to main content

Crate bevy_resvg

Crate bevy_resvg 

Source
Expand description

§Bevy Resvg

A simple library for rendering SVGs in Bevy using the amazing Resvg library.

Crates.io Documentation Bevy Version Dependency Status

§Why not bevy_svg?

I originally tried forking bevy_svg to add colour tinting support to the SVGs, as proposed by bevy_svg/#54. However, I quickly noticed that the bevy_svg had so much technical debt (no offense to Weasy666, your library has clearly worked for many, many people) due to its 5 years of existence that it was just easier to start a new library from scratch.

Funnily enough, I’m actually publishing this crate onto crates.io on bevy_svg’s 5-year anniversary (January 24th)!

Bevy Resvg takes a completely different approach to rendering SVGs compared to bevy_svg. Instead of tessellating the SVG into a mesh, it first renders the SVG as a raster image using the Resvg library.

§Why not Bevy Vello then?

I actually only found out about Bevy Vello after publishing this crate. For those unaware (like I was earlier!), Bevy Vello is a Bevy plugin that can render numerous types of vector graphics, from text to SVGs to even Lotties using the Vello crate. Vello focuses on GPU compute, making it very quick. Thanks to this performance, it can perform Just-in-Time (JIT) rasterisation of the vector graphics, allowing for crisp graphics at any resolution.

However, Vello isn’t perfect. Most importantly, it doesn’t support as much of the Static SVG Spec as Resvg does. If you need to load complex SVGs, Bevy Resvg is simply going to be the best choice.

Here’s a complete comparison between the three:

§Comparison between Bevy Resvg, bevy_svg, and Bevy Vello

FeatureBevy Resvgbevy_svgBevy Vello
Source Lines of Code🔽9381🔼190412636113
Code Complexity😀601😵‍💫14512😵40913
Hot-reloading of SVGsSupportedSupportedUnsupported
Changing runtime colourSupportedUnsupportedUnsupported
Custom CSS injectionSupportedUnsupportedUnsupported
GradientsSupportedUnsupported⚠️Inaccurate
Semi-transparencySupportedUnsupportedSupported
Positioning and sizingNative (Sprite & ImageNode-based)Janky and impreciseNative (Image-based)
Static SVG Spec SupportFully Supported⚠️Partial Support⚠️Partial Support
Rendered quality (normal)CrispCrispCrisp
Rendered quality (zoomed)Blurry and PixelatedCrispCrisp
3D-RenderingUnsupportedSupportedSupported
Animated SVGsUnsupportedUnsupportedUnsupported
Approach🖼️Rasterisation (once)🔺Tessellation⚙️Rasterisation (JIT every frame)
Output🏃‍➡️Sprite (2D) or ImageNode (UI)🕸Mesh2d🔀Mesh2d with image-based texture
Licence🟰MIT OR Apache-2.0🟰MIT OR Apache-2.0🟰MIT OR Apache-2.0

[!NOTE] In order to be able to hot-reload your SVGs, you must enable the file_watcher BEVY FEATURE (not a feature available in this crate).

As a side note, you probably want to enable entire dev collection (again, the Bevy feature, there is no feature called dev in this crate). It comes with a handful of goods, including debug logs and dev tools.

…to be expanded…

§Okay, but when should I actually use Bevy Resvg over the others?

This is a very complex question to answer. Your best bet is probably going to be to just add one to your list of dependencies and try it out; all three projects are quite interchangeable with each other.

If you’re not up for waiting for 3 separate crates to compile, and you want some more concrete examples than the comparison table above, then check out some of the longer explanations below.

§When to use Bevy Resvg over bevy_svg

Although I am very proud of this small little crate (it’s my first ever library to be published on crates.io)!, I do realise that there are situations in which bevy_svg simply makes more sense.

For starters, Bevy Resvg is a very young and immature project. If you are looking for something more mature and battle-tested, you should probably use bevy_svg.

Another feature missing from Bevy Resvg is 3D rendering, which has first-class support in bevy_svg. Unfortunately, you can’t easily render to 3D objects with Bevy Resvg, yet. Don’t worry, it’s on the Todo-list! In the meantime, check out bevy_svg if you need to render to a 3D object.

Furthermore, if your game is dependent on zooming into the SVGs, bevy_svg might fit your needs better. Bevy Resvg only performs rasterisation once, mimicking the behaviour of e.g. the Godot Engine. This has the unfortunate side-effect of causing blurry images when zooming in. bevy_svg, however, tessellates the SVGs into a crisp Mesh2d, which results in sharper rendering when zoomed in.

If you wish to mitigate the blur, you can set a custom target render size via SvgFileLoaderSettings.target_render_size. This allows you to render a larger image up front. However, this has the caveat of requiring you to manually determine how far a user is likely to zoom in on your SVGs. See the custom_size example for a demonstration of this.

However, if you are in need of rendering semi-transparent SVGs, then Bevy Resvg is your only option (to my knowledge). Perhaps you even want to change the runtime colour of your loaded SVGs. In that case, Bevy Resvg makes it super simple! Just modify the outputted Sprite’s color field and you’ve got yourself a tinted SVG! That’s not possible (again, to my knowledge) in bevy_svg. What about gradients? No problem! Resvg handles gradients naturally too.

I’m not sure why (and, like many other things in this project, I haven’t bothered to test why), but positioning and especially sizing SVGs with bevy_svg as children of sprites felt clunky and required hard-coded values back when I used bevy_svg. I have yet to encounter that issue with Bevy Resvg.

Also, although I have no data to back this up, I would assume that Bevy Resvg might be a tiny bit faster than bevy_svg. Meshes feel more expensive than simple textures to me, however I am no expert in this area.

During testing, I found that bevy_svg couldn’t load complex Inkscape-generated SVGs, while Bevy Resvg handled them flawlessly just like any other SVG file. Although you should not ship Inkscape-generated SVGs in your released game, it can be beneficial to not have to export your SVGs as standard SVGs from Inkscape each time you want to test a new design.

§When to use Bevy Resvg over Bevy Vello

To be written…

§Usage

See the examples directory for examples of how to use the Bevy Resvg.

Currently, the only examples are:

  • color_change: shows how to update the colour tint of an Svg when an event (spacebar pressed) occurs
  • color_hue_tween: showcase of an Svg that continuously tweens through all hues
  • color_ui_change: shows how to update the colour tint of a UiSvg when an event (spacebar pressed) occurs
  • color_ui_hue_tween: showcase of an UiSvg that continuously tweens through all hues
  • color_ui: shows how to apply a static colour tint to a UiSvg
  • color: shows how to apply a static colour tint to an Svg
  • crisp_shapes: shows how to customise usvg::Options to render SVGs with crisp edges and with anti-aliasing turned off.
  • custom_aspect_ratio: shows how to render an SVG to a custom target size with a non-native aspect ratio
  • custom_size: shows how to render an SVG to a custom target size
  • custom_style_sheet: shows how to customise usvg::Options while loading an SVG by setting style_sheet
  • simple: shows the most basic usage of Bevy Resvg
  • ui: shows how to render UiSvgs in UI nodes
  • zoom: shows what happens when you zoom too far into an SVG

More examples are planned!

If you’re too lazy to click the link, here’s the contents of simple.rs:

use bevy::prelude::*;
use bevy_resvg::prelude::*;

fn main() {
    App::new()
        .add_plugins((DefaultPlugins, SvgPlugin))
        .add_systems(Startup, setup)
        .run();
}

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
    let svg: Handle<SvgFile> = asset_server.load("transparent.svg");
    commands.spawn(Camera2d);
    commands.spawn(Svg(svg));
}

§Migration guide from bevy_svg

If you wish to migrate from bevy_svg to Bevy Resvg, you must do the following actions:

[!IMPORTANT] 3D rendering is not yet supported in Bevy Resvg.

  1. Run cargo remove bevy_svg and cargo add bevy_resvg.
  2. If you were just using bevy_svg::prelude in your code, simply replace it with bevy_resvg::prelude.
  3. Replace all occurrences of Svg with SvgFile (make sure you’re doing whole-word replacing. You don’t want an SvgFilePlugin!).
  4. Replace all occurrences of Svg2d with either Svg or UiSvg (depending on how you’re using it). This step requires a bit of care so that you don’t use the wrong one!

§Todos

  • 3D-Rendering support
  • JIT support! (because it’s cool, I doubt that it is performant lol)
  • Add more examples
  • Add tests (there are currently none…)
  • Custom rendering size targets (not dependent on viewBox value)
  • UI rendering
  • Expand comparison table
    • Particularly, add performance comparisons
  • Handle more AssetEvents
    • Added
    • Modified
    • Removed
    • Unused
    • LoadedWithDependencies
  • usvg::Options support 4
    • CSS support

§Minimum supported Rust version

Bevy Resvg’s MSRV is 1.89 due to Bevy’s MSRV.

§Contributing

See CONTRIBUTING.md.

§Licence

MIT OR Apache-2.0, at your option.


  1. Calculated using scc, only counting Rust code. ↩ 1 2 3 4 5 6

  2. Based on commit b3a3748 in Weasy666/bevy_svg ↩ 1 2

  3. Based on tagged release v0.13.0 in linebender/bevy_vello because later versions of Bevy Vello refuse to compile on my machine. ↩ 1 2

  4. The advanced image_href_resolver, font_resolver, and fontdb settings are not available due to missing serde support in usvg. If you require changing these settings, please use the resvg-option branch. It’s unfortunately not released on crates.io due to it [patch]ing usvg, which is not allowed on crates.io. Please follow the instructions in resvg-option/USAGE.md to set up resvg-option

Re-exports§

pub use resvg;

Modules§

effects
Runtime modification of SVG files.
error
Error utilities for this crate.
plugin
The Plugin for initialising the Bevy logic and configuration provided by this crate.
prelude
Import this module as use bevy_resvg::prelude::* to get convenient imports.
raster
Tools and helpers for loading, rastering, and rendering SVG files.
settings
AssetLoader settings for SvgFile