Early alpha — under heavy development. Expect some breaking changes between releases.

Eido

Describe what you see as plain data

From Greek eido — "I see"

Images are values
A scene is a plain data structure — printable, serializable, diffable. Nothing opaque.
One function
render takes a scene (or a sequence of scenes) and produces output. That's the entire API.
Description, not instruction
You declare what the image contains — Eido decides how to draw it.
Animations are sequences
60 frames = 60 scenes in a list. No timeline, no keyframes, no mutable state.
Particle simulation
Physics-based effects — fire, snow, sparks — configured as data with deterministic results.
Typography as paths
Text converted to vector paths — compatible with gradients, transforms, and 3D extrusion.
Bring your own workflow
Every function takes data and returns data. No framework, no state management.
Zero dependencies
Just the language and the standard library. Nothing to install, nothing to break.

How it works

In Eido, an image is just a description — a plain data structure that says what the image contains. Here's a red circle on a light background:

{:image/size [400 400]                       ;; 400x400 pixels
 :image/background [:color/rgb 245 243 238]  ;; warm off-white
 :image/nodes
 [{:node/type     :shape/circle
   :circle/center [200 200]                  ;; center of the canvas
   :circle/radius 120
   :style/fill    [:color/rgb 200 50 50]}]}  ;; red fill

That's it — no drawing commands, no canvas API, no mutable state. You describe what you see, and Eido renders it. To produce an image file:

(eido/render scene {:output "circle.png"})

Want animation? Return a different scene for each frame. Here's a circle that grows and shifts color over 60 frames:

(def frames
  (anim/frames 60
    (fn [t]                             ;; t goes from 0.0 to 1.0
      {:image/size [400 400]
       :image/background [:color/rgb 30 30 40]
       :image/nodes
       [{:node/type     :shape/circle
         :circle/center [200 200]
         :circle/radius (* 150 t)       ;; grows over time
         :style/fill [:color/hsl        ;; hue shifts through
                      (* 360 t)         ;;   the rainbow
                      0.8 0.5]}]})))

(eido/render frames {:output "grow.gif" :fps 30})

Every example in the gallery works this way — pure data in, image out.

Installation

io.github.leifericf/eido {:git/tag "v1.0.0-alpha5" :git/sha "03b38ab"}