Skip to content


Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


Victor - Ruby SVG Image Builder

Gem Version Build Status Maintainability

Victor is a direct Ruby-to-SVG builder. All method calls are converted directly to SVG elements.


Table of Contents


$ gem install victor

Or with bundler:

gem 'victor'


require 'victor'

svg = width: 140, height: 100, style: { background: '#ddd' } do 
  rect x: 10, y: 10, width: 120, height: 80, rx: 10, fill: '#666'
  circle cx: 50, cy: 50, r: 30, fill: 'yellow'
  circle cx: 58, cy: 32, r: 4, fill: 'black'
  polygon points: %w[45,50 80,30 80,70], fill: '#666'

  3.times do |i|
    x = 80 + i*18
    circle cx: x, cy: 50, r: 4, fill: 'yellow'
end 'pacman'



See the examples folder for several ruby scripts and their SVG output.


Initialize your SVG image:

require 'victor'
svg =

Any option you provide to will be added as an attribute to the main <svg> element. By default, height and width are set to 100%.

svg = width: '100%', height: '100%'
# same as just

svg = width: '100%', height: '100%', viewBox: "0 0 200 100"

As an alternative, you can set the root SVG attributes using the setup method:

require 'victor'
svg =
svg.setup width: 200, height: 150

Victor uses a single method (element) to generate all SVG elements:

svg.element :rect, x: 2, y: 2, width: 200, height: 200
# => <rect x="2" y="2" width="200" height="200"/>

But you can omit it. Calls to any other method, will be delegated to the element method, so normal usage looks more like this:

svg.rect x: 2, y: 2, width: 200, height: 200
# => <rect x="2" y="2" width="200" height="200"/>

In other words, these are the same:

svg.element :anything, option: 'value'
svg.anything option: 'value'

You can use the build method, to generate the SVG with a block do 
  rect x: 0, y: 0, width: 100, height: 100, fill: '#ccc'
  rect x: 20, y: 20, width: 60, height: 60, fill: '#f99'

If the value of an attribute is a hash, it will be converted to a style-compatible string:

svg.rect x: 0, y: 0, width: 100, height: 100, style: { stroke: '#ccc', fill: 'red' }
# => <rect x=0 y=0 width=100 height=100 style="stroke:#ccc; fill:red"/>

If the value of an attribute is an array, it will be converted to a space delimited string:

svg.path d: ['M', 150, 0, 'L', 75, 200, 'L', 225, 200, 'Z']
# => <path d="M 150 0 L 75 200 L 225 200 Z"/>

For SVG elements that have an inner content - such as text - simply pass it as the first argument:

svg.text "Victor", x: 40, y: 50
# => <text x="40" y="50">Victor</text>

You can also nest elements with blocks: do
  g font_size: 30, font_family: 'arial', fill: 'white' do
    text "Scalable Victor Graphics", x: 40, y: 50
# => <g font-size="30" font-family="arial" fill="white">
#      <text x="40" y="50">Scalable Victor Graphics</text>
#    </g>

Underscores in attribute names are converted to dashes:

svg.text "Victor", x: 40, y: 50, font_family: 'arial', font_weight: 'bold', font_size: 40
# => <text x="40" y="50" font-family="arial" font-weight="bold" font-size="40">
#      Victor
#    </text>


Composite SVG

Victor also supports the ability to combine several smaller SVG objects into one using the << operator or the #append method.

This operator expects to receive any object that responds to #to_s (can be another SVG object).

require 'victor'
include Victor

# Create a reusable SVG object
frame =
frame.rect x: 0, y: 0, width: 100, height: 100, fill: '#336'
frame.rect x: 10, y: 10, width: 80, height: 80, fill: '#fff'

# ... and another
troll = cx: 50, cy: 60, r: 24, fill: 'yellow'
troll.polygon points: %w[24,50 50,14 76,54], fill: 'red'

# Combine objects into a single image
svg = viewBox: '0 0 100 100'
svg << frame
svg << troll

# ... and save it 'framed-troll'



These two calls are identical:

svg << other
svg.append other

To make this common use case a little easier to use, you can use a block when instantiating a new SVG object:

troll = do
  circle cx: 50, cy: 60, r: 24, fill: 'yellow'

Which is the same as:

troll = do
  circle cx: 50, cy: 60, r: 24, fill: 'yellow'

Another approach to a more modular SVG composition, would be to subclass Victor::SVG.

See the composite svg example or the subclassing example for more details.

Saving the Output

Generate the full SVG to a string with render:

result = svg.render

Or, save it to a file with save: 'filename'
# the '.svg' extension is optional

SVG Templates

The :default SVG template is designed to be a full XML document (i.e., a standalone SVG image). If you wish to use the output as an SVG element inside HTML, you can change the SVG template:

svg = template: :html 
# accepts :html, :minimal, :default or a filename

You can also point it to any other template file:

svg = template: 'path/to/template.svg'

See the templates folder for an understanding of how templates are structured.

Templates can also be provided when rendering or saving the output: 'filename', template: :minimal
svg.render template: :minimal


CSS gets a special treatment in Victor::SVG, with these objectives in mind:

  • Hide implementation details (such as the need for a CDATA marker)
  • Provide a DSL-like syntax for CSS rules

The Victor::SVG objects has a css property, which can contain either a Hash or a String:

svg =

svg.css = css_hash_or_string
# or without the equal sign:
svg.css css_hash_or_string do
  # ...

This flexibility allows you to apply CSS in multiple ways. Below are some examples.

Assigning CSS rules using the hash syntax

svg = do 
  css['.main'] = {
    stroke: "green", 
    stroke_width: 2,
    fill: "yellow"

  circle cx: 35, cy: 35, r: 20, class: 'main'

Assigning a full hash to the CSS property

svg.css = {
  '.bar': {
    fill: '#666',
    stroke: '#fff',
    stroke_width: 1
  '.negative': {
    fill: '#f66'
  '.positive': {
    fill: '#6f6'

Underscore characters will be converted to dashes (stroke_width becomes stroke-width).

Importing CSS from an external file

svg.css = 'styles.css'

CSS @import directives

If you need to add CSS statements , like @import, use the following syntax:

css['@import'] = [

This is achieved thanks to the fact that when Victor encounters an array in the CSS hash, it will prefix each of the array elements with the hash key, so the above will result in two @import url(...) rows.

See the css example, css string example, or the custom fonts example.

Tagless Elements

Using underscore (_) as the element name will simply add the value to the generated SVG, without any surrounding element. This is designed to allow generating something like this:

  You are
  <tspan font-weight="bold">not</tspan>
  a banana

using this Ruby code: do 
  text do
    _ 'You are'
    tspan 'not', font_weight: "bold"
    _ 'a banana'

See the tagless elements example.

XML Encoding

Plain text values are encoded automatically: do
  text "Ben & Jerry's"
# <text>Ben &amp; Jerry's</text>

If you need to use the raw, unencoded string, add ! to the element's name: do
  text! "Ben & Jerry's"
# <text>Ben & Jerry's</text>

See the xml encoding example.

XML Newlines

By default, the generated SVGs will have a newline glue between the elements. You can change this (for example, to an empty string) if the default newlines are not appropriate for your use case.

svg = glue: ''

The glue can also be provided when rendering or saving the output: 'filename', glue: ''
svg.render glue: ''

DSL Syntax

Victor also supports a DSL-like syntax. To use it, simply require 'victor/script'.

Once required, you have access to:

  • svg - returns an instance of Victor::SVG
  • All the methods that are available on the SVG object, are included at the root level.

For example:

require 'victor/script'

setup width: 100, height: 100

build do
  circle cx: 50, cy: 50, r: 30, fill: "yellow"

puts render
save 'output.svg'

See the dsl example.

Using with Rails

See the example_rails folder.

Related Projects

Victor CLI

A command line utility that allows converting Ruby to SVG as well as SVG to Victor Ruby scripts.

Victor Opal

A Victor playground that works in the browser.


A Ruby gem that uses Victor to generate SVG charts



A Ruby gem that uses Victor to generate consistent random icon images, similar to GitHub's identicon.


Contributing / Support

If you experience any issue, have a question or a suggestion, or if you wish to contribute, feel free to open an issue.