Skip to content

Nim-based DSL allowing to generate SVG files and GIF animations.

Notifications You must be signed in to change notification settings

sdmcallister/NimSvg

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

88 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NimSvg Build Status

Nim-based DSL allowing to generate SVG files and GIF animations.

DSL

NimSvg is inspired by Karax, and offers a similar DSL to generate SVG trees. A simple hello world

import nimsvg

buildSvgFile("examples/basic1.svg"):
  svg(width=200, height=200):
    circle(cx=100, cy=100, r=80, stroke="teal", `stroke-width`=4, fill="#EEF")

produces the following SVG:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "https://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="200" height="200">
  <circle cx="100" cy="100" r="80" stroke="teal" stroke-width="4" fill="#EEF"/>
</svg>

Output:

basic1

The DSL allows to mix tag expressions with regular Nim expressions like variable definitions, for loops, or if statements, which makes it easy to generate SVGs programmatically:

import nimsvg, random

buildSvgFile("examples/basic2.svg"):
  let size = 200
  svg(width=size, height=size):
    for _ in 0 .. 1000:
      let x = rand(size)
      let y = rand(size)
      let radius = rand(5)
      circle(cx=x, cy=y, r=radius, stroke="#111122", fill="#E0E0F0", `fill-opacity`=0.5)

Output:

basic2

NimSvg also allows to render a sequence of SVG files into an animated GIF (requires Imagemagick for the rendering):

import nimsvg

let settings = animSettings("filenameBase", backAndForth=true)
let numFrames = 100

settings.buildAnimation(numFrames) do (i: int) -> Nodes:
  let w = 200
  let h = 200
  buildSvg:
    svg(width=w, height=h):
      let r = 0.4 * w.float * i.float / numFrames.float + 10
      circle(cx=w/2, cy=h/2, r=r, stroke="#445", `stroke-width`=4, fill="#EEF")

Output:

animation1

Special syntax

  • t: The t keyword can be used to create text nodes:

    let svg = buildSvg:
      text(x=0, y=0):
        t "Hello World"
  • embed: The embed keyword can be used to embed the result of other nodes.

    proc sub(): Nodes = buildSvg:
      b()
      c()
    
    let svg = buildSvg:
      # produces tags <a><b><c><d>
      a()
      embed sub()
      d()

Gallery

Click on an image to see the corresponding implementation.

spinner1 spinner2 spinner3

Example algorithm visualization of rust-array-stump:

algo-viz-1

JS

Compile to JS nim js main.nim

main.nim:

import nimsvg
import std/dom

proc makeSVG(){.exportc.} =
  let x = buildSvg:
    svg(width = 200, height = 200):
      circle(cx = 100, cy = 100, r = 80, stroke = "teal", `stroke-width` = 4, fill = "#EEF")
  document.getElementById("SVG").innerHTML = x.render()

index.html:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>SVG</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
  <div id="SVG"></div>
  <button onclick="makeSVG()">make svg</button>
  <script src="main.js" async defer></script>
</body>

</html>

Currently does not support features that require file access.

About

Nim-based DSL allowing to generate SVG files and GIF animations.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Nim 98.9%
  • Shell 1.1%