Skip to content
 
 

Repository files navigation

Mac

Meme as Code. A programming language where memes are first-class citizens.

@two_panel {
    top: "Me: it works on my machine"
    bottom: "Prod: lol no"
} |> glitch => "meme.png"

Install

curl -fsSL https://macstudio.meme/install.sh | bash

Or build from source:

cmake -S . -B build && cmake --build build

Grammar

Every meme expression follows a composable grammar. Here's how all the pieces fit together:

Meme Literal

@<template> [WxH] [style] { top: "..." bottom: "..." }  [|> effect]  [=> "path"]
@<template> [WxH] [style] "one-liner text"               [|> effect]  [=> "path"]
@"path/to/image.png" [WxH] [style] { ... }               [|> effect]  [=> "path"]
@blank "Hello"                                    // minimal
@two_panel { top: "A" bottom: "B" }               // block with positions
@square 800x800 { top: "Sized" }                  // with dimensions
@dark neon { top: "Styled" }                      // with style
@dark 800x800 neon { top: "All" } |> glitch       // size + style + effect
@"photo.png" { top: "Custom" } => "out.png"       // custom template + save

Effect Preset

effect <name> = <effect> >> <effect> >> ... ;
effect glitch = pixelate(4) >> contrast(1.8) >> noise(0.2);
effect vintage = sepia >> brightness(0.9);
effect cyberpunk = hueShift(180) >> contrast(1.5) >> chromatic(3) >> glow(4);

Style Block

style <name> {
    color: "#RRGGBB"
    outline: <pixels>
    outlineColor: "#RRGGBB"
    shadow: <offset>
    shadowColor: "#RRGGBBAA"
}
style neon {
    color: "#00FF41"
    outline: 4
    outlineColor: "#003300"
    shadow: 3
    shadowColor: "#00FF4180"
}

GIF Block

gif [loop] {
    <meme> [|> effect] : <duration> [sound <name-or-path>]
    --- <transition> <duration> [easing] [sound <name-or-path>] ---
    <meme> [|> effect] : <duration> [sound <name-or-path>]
    ...
} [=> "path"]
gif loop {
    @blank "3" : 500ms
    @blank "2" : 500ms
    @blank "GO!" : 1s
} => "countdown.gif"

Add --- transition --- separators between entries for a cross-faded sequence:

gif loop {
    @two_panel { top: "Act 1" } |> vintage : 3s
    --- crossfade 300ms ease ---
    @two_panel { top: "Act 2" } |> glitch : 3s
    --- fadeBlack 400ms ---
    @blank "fin." : 2s
} => "story.gif"

MP4 Output and Sound Cues

Save with .mp4 for H.264 video (requires ffmpeg on your PATH). Sound cues only reach the output in an MP4, since GIF cannot carry audio - saving a cue-bearing animation to .gif warns and drops the cues.

gif {
    @dark "step one" : 2s sound ding
    --- slideLeft 300ms easeOut sound whoosh ---
    @dark "narrated" : sound narration
    @dark "done" : 2s sound chime
} => "steps.mp4"

A duration of sound <name> holds the frame for the bite's own length (clamped to 10s); the same works on a transition. Bites resolve as a built-in name (ding), a dotted name (acme.jingle from assets/sounds/acme/jingle.*), or a quoted script-relative path (sound "audio/x.wav").

Edit Block - Video Clips

An edit block is a gif block that also takes video footage. Clips are sampled at 30fps, trimmed with start..end, captioned onto every frame, and mixed freely with still frames and transitions. A clip's own audio comes along automatically. Requires ffmpeg on your PATH.

edit loop {
    caption "three weeks earlier" : 1s
    --- fadeBlack 400ms ---
    clip "footage.mp4" trim 2s..8s caption "when the build goes green"
    --- crossfade 300ms ---
    @dark "the end" : 1s
} => "reaction.mp4"

A clip has no : duration - its length comes from the footage. A caption with no clip before it is a text card on a blank background. Clips sample at full frame rate, capped at 9000 source frames (five minutes), and going over errors rather than truncating. Everything is re-encoded to H.264 once, and footage above 30fps loses frames.

Grid Block

grid <cols>x<rows> {
    <meme> [|> effect]
    <meme> [|> effect]
    ...
} [|> pad(n)] [|> border(n)] [=> "path"]
grid 2x2 {
    @blank "A" |> sepia
    @blank "B" |> glitch
    @blank "C" |> vintage
    @blank "D" |> deepfry
} |> pad(5) |> border(2) => "grid.png"

Layout Operators

beside(<meme>, <meme>)     // side by side
stack(<meme>, <meme>)      // vertical
<expr> |> pad(<px>)        // padding
<expr> |> border(<px>)     // border

Pipe & Compose

<expr> |> <fn>                          // pass as first arg
<expr> |> <fn>(args) |> <fn> ...        // chain
<fn> >> <fn> >> <fn>                    // compose into new function

Functional Pipelines

<array> |> map(<fn>)                    // transform each
<array> |> filter(<fn>)                 // keep matches
<array> |> reduce(<fn>, <init>)         // fold to value
<array> |> zip(<array>)                 // pair elements
["Mon", "Tue", "Wed"]
    |> map(d -> @two_panel { top: d })
    |> reduce((g, m) -> g.frame(m, Duration(500)), Gif())
    |> save("week.gif")

Save Operator

<expr> => "filename.png"       // save to ~/mac/output/
<expr> => "filename.gif"       // auto-detects format
<expr> => "subdir/file.png"    // explicit relative path
<expr> => "/tmp/file.png"      // explicit absolute path

If MAC_OUTPUT_DIR is set, saves are redirected there and only the filename portion is kept.

Reference

Element Options
Templates two_panel three_panel bottom_text blank dark wide tall square four_panel caption_bar or @"path"
Positions top bottom center
Effects (param) blur(n) pixelate(n) noise(n) saturate(n) contrast(n) brightness(n) jpeg(n) hueShift(n) glow(n) posterize(n) chromatic(n) threshold(n) tint(n)
Effects (direct) invert sepia sharpen vignette grayscale deepfry
Transitions crossfade slideLeft slideRight slideUp slideDown wipe fadeBlack zoom
Easing linear ease easeIn easeOut easeInOut bounce
Durations 400ms 2s Duration(400) or sound <bite> (the bite's own length)
Sizes 800x600 Size(800, 600)
Sound bites whoosh ding chime riser boom record_scratch click error or acme.jingle / "audio/x.wav"
Output formats .png .gif .mp4 (mp4 needs ffmpeg; only mp4 carries sound)
Clip sources .mp4 .mov .m4v .webm .mkv .avi (needs ffmpeg; sampled at 30fps)

Language

Mac is a dynamically typed language with functions, closures, classes, arrays, maps, arrow functions, pipes, and operator overloading.

See LANGUAGE.md for the full reference.

VS Code Extension

Syntax highlighting, LSP (hover, go-to-definition, inlay hints, semantic tokens, signature help, find references, document symbols), snippets, and file icons.

cd mac-lang && npm install && npx tsc && cd ..
ln -sf "$(pwd)/mac-lang" ~/.vscode/extensions/mac-lang

Development

cmake --build build && bash tests/run_tests.sh

See docs/BUILDING.md and docs/ARCHITECTURE.md.

License

MIT

About

Meme as Code. A programming language where memes are first-class citizens.

Resources

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages