Linocut makes pictures from code and from files, for games on cauldron_2d. It does for sprites what tuning_fork does for sound. You write the picture as notation in Elixir. Pure functions render it. A disk cache keeps the result, and a mix task shows it in the terminal.

Where it fits

Every result is a FrenchCurve.Raster from french_curve. Cauldron2D.Atlas.put/4 takes one as it is. cauldron_2d reads an art directory's .pic files and Linocut.Derive lines when it loads an atlas. The easel editors edit the same .pic files: cauldron_2d_easel and its terminal, browser and Livebook front ends.

Installation

Add the dependency to mix.exs:

def deps do
  [
    {:linocut, "~> 0.3"}
  ]
end

Usage

ship =
  Linocut.sprite("""
  ..RR..
  .RWWR.
  RRWWRR
  """, R: "#c33", W: :white)

headings = Linocut.headings([{15, 0}, {-8, 8}, {-8, -8}], 64, size: {16, 16}, fill: "#e8e8e8")
red_team = Linocut.recolour(ship, %{{204, 51, 51, 255} => {51, 51, 204, 255}})
spin = Linocut.Strip.new(headings, 30)

atlas = Cauldron2D.Atlas.put(atlas, :ship, ship)

What is here

NameWhat it does
Linocut.sprite/3Draws a picture from text and a palette legend. . and space are transparent.
Linocut.outline/2Draws a filled or stroked shape from its points. x goes right and y goes up.
Linocut.headings/3Draws the shape at every heading. Heading 0 points right, and headings turn counter-clockwise.
Linocut.recolour/2, tint/3, scale/2, squash/3, flip/2, rotate/2, transform/3Make a new raster from any raster.
Linocut.frames/2Cuts a raster into frames of one size.
Linocut.load/2, Linocut.pic/2Read a .png or .pic file, or .pic text, into a raster.
Linocut.PaletteReads colours: "#c33", :cyan, {r, g, b} or {r, g, b, a}.
Linocut.FontWrites names, numbers and notes on a picture in a three-by-five pixel font.
Linocut.PngReads PNG files into a raster.
Linocut.DeriveMakes a picture from another with one line of operations on its keys, such as from knight; colour C #c02020; flip h.
Linocut.PicReads and writes the .pic file. A .pic is a palette, a blank line, then the picture. Frames are separated by ---.
Linocut.StripPlays frames at a rate, looping.
Linocut.CacheRenders rasters once and keeps them under ~/.cache/linocut.
Linocut.PreviewLays many rasters on one sheet. It writes the sheet to the terminal or to a PNG.
Linocut.QuantiseReduces a picture to a small palette, chosen by median cut over its opaque pixels.
Linocut.SheetCuts a sprite sheet into frames. It finds them between blank rows and blank columns.
Linocut.FramesLines up the frames of one animation on one canvas, standing on the same floor. It writes them as a .pic with a shared palette.
Linocut.PoseHolds a figure's joints. It draws the OpenPose skeleton that a ControlNet reads.
Linocut.ResampleRedraws a picture at another size, by area or by nearest pixel.
Linocut.SeamMakes a picture repeat without a visible join. It fades the far edge into the near one.
mix linocut.viewShows pictures in the terminal (see below).
mix linocut.importTurns an image file into a .pic at a chosen size and palette.
mix linocut.sheetCuts a sprite sheet into the frames of one .pic.
mix linocut.joinJoins separately drawn pictures into the frames of one .pic.
mix linocut.poseWrites OpenPose skeletons for an animation cycle, one PNG a frame.

Deriving

A .pic is made of keys, and each key means something. C is the cloak, whatever colour it is. So a second view of a picture is one line, not a second drawing:

from knight; colour C #c02020            the same knight in red
from knight; flip h                       facing the other way
from knight; over hat 0 -2                with a hat on
from walk; frame 3                        one frame of an animation

The other operations are swap KEY KEY, turn 90|180|270, shift DX DY, scale N and reverse. reverse puts the frames in the other order.

Linocut.Derive.derive/2 runs a line. It takes a function that gives the text behind each name. Cauldron2D.Atlas.load/3 reads the same lines from the fifth field of atlas.txt. It builds the derived arts after the drawn ones.

The operations work on the text of the picture, not its pixels. Nothing is rendered until the atlas is built. A derived picture is a picture like any other.

Looking at it

mix linocut.view ship.exs
mix linocut.view priv/art
mix linocut.view ship.exs --scale 3 --columns 8 --protocol braille

mix linocut.view shows pictures in this terminal. Give it a script whose last expression is a raster, a list of rasters or a strip. You can also give it a .png or .pic file, or a directory of them. --protocol picks kitty, iterm2, sixel or braille; by default it is detected. The example script is in examples.

License

MIT