Zixir is a small, expression-oriented language and a three-tier runtime that combines:
- Elixir (orchestrator) - For concurrency, fault tolerance, and intent
- Zig (engine) - For memory-critical math and high-speed data operations
- Python (specialist) - For accessing Python libraries and ecosystem
- Array-heavy and numeric work — Sums, products, dot products, and similar ops run in the Zig engine (NIFs), often 100–1000× faster than doing the same in pure Elixir. Use
engine.list_sum,engine.list_product,engine.dot_productfor hot paths. - One language, three backends — You write Zixir; the runtime picks Elixir for orchestration, Zig for fast math, and Python when you need a library. No need to hand-write C/Zig bindings for every Python or numeric kernel.
- Pipelines that mix math and ecosystem — Express formulas and data steps in Zixir, call out to Python (e.g. numpy, plotting, APIs) where needed, and let the engine handle the heavy numeric parts.
- Scripts and small tools — A single Zixir program can do arithmetic, aggregate over arrays, and call Python for I/O or visualization, with predictable performance where it matters.
| Use case | Why Zixir fits |
|---|---|
| Data processing / analytics | Engine ops for aggregates and dot products; Python for pandas/numpy or plotting when needed. |
| Simulation / game math | Positions, velocities, and dot products in the engine; game loop in Elixir; display or UI in Python (e.g. tkinter, pygame). |
| Scientific or numerical scripting | Write formulas in Zixir, use the engine for hot loops, call Python for scipy/numpy or file formats. |
| Tooling and automation | Elixir orchestrates steps; Zixir handles numeric logic; Python handles formats, APIs, or GUIs. |
| Learning or teaching | One syntax that spans “math” (Zixir), “fast kernel” (Zig), and “ecosystem” (Python) in a single runtime. |
As the language grows (e.g. functions, control flow, more engine ops), it will fit larger programs and more domains while keeping the same three-tier split.
Zixir fits specific areas of game development rather than replacing a full engine:
| Area | How Zixir helps |
|---|---|
| Game math / physics | Positions, velocities, dot products, and aggregates run in the Zig engine (NIFs). Use engine.list_sum, engine.dot_product for movement, scoring, or collision-style math. The language expresses the formulas; the engine runs them fast. |
| Prototyping & small games | Elixir runs the loop; Zixir (or .zr scripts) computes state each frame; Python (tkinter, pygame) handles display and input. Good for 2D prototypes, tools, and learning. |
| Simulation & numeric logic | Damage formulas, stats, economy, or any numeric game logic can live in Zixir and hit the engine for hot paths. Elixir coordinates; Python is only for I/O or rendering. |
| Game tooling & pipelines | Level data, balance tables, or asset pipelines: Elixir orchestrates; Zixir does numeric/aggregate logic; Python handles file formats or scripting. |
| Server-side game logic | For matchmaking, scoring, or stats, Elixir's concurrency plus Zixir + engine for numeric work can handle server-side game logic without Python in the hot path. |
Zixir is not aimed at building a full AAA engine (no 3D renderer, no custom low-level loop in Zixir yet). It is a good fit for: game math, 2D prototypes, simulation, tooling, and server-side numeric logic—all with one language and a clear split between fast kernels (Zig) and ecosystem (Python).
# 1. Install dependencies
mix deps.get
# 2. Install Zig (via Zigler)
mix zig.get
# 3. Compile the project
mix compile
# 4. Run tests
mix testCreate a file hello.zr:
# Basic arithmetic
let x = 10
let y = 5
x + y
# Result: 15
Run it:
mix zixir run hello.zrOr use the Elixir API:
Zixir.run("let x = 10\nlet y = 5\nx + y")
# => 15# This is a comment
# Comments start with # and go to end of line
let x = 42 # Integer
let pi = 3.14159 # Float
let name = "Zixir" # String
let items = [1, 2, 3] # Array
Numbers:
42 # Integer
3.14 # Float
Strings:
"hello world"
"line 1\nline 2" # With escape sequences
Arrays:
[1, 2, 3]
[1.0, 2.0, 3.0] # Arrays of floats for engine operations
Booleans:
true
false
1 + 2 # Addition
10 - 5 # Subtraction
4 * 3 # Multiplication
8 / 2 # Division
High-performance operations implemented in Zig:
# Sum of array elements
engine.list_sum([1.0, 2.0, 3.0])
# => 6.0
# Product of array elements
engine.list_product([2.0, 3.0, 4.0])
# => 24.0
# Dot product of two arrays
engine.dot_product([1.0, 2.0, 3.0], [4.0, 5.0, 6.0])
# => 32.0
# String length (byte count)
engine.string_count("hello")
# => 5
Call Python libraries directly:
# Call Python math.sqrt
python "math" "sqrt" (16.0)
# => 4.0
# Call numpy functions
python "numpy" "mean" ([1.0, 2.0, 3.0, 4.0, 5.0])
# => 3.0
# Compile a .zr file to binary
mix zixir compile program.zr
# Compile and run immediately
mix zixir run program.zr
# Run with verbose output
mix zixir run program.zr --verbose
# Type check only
mix zixir check program.zr
# Start interactive REPL
mix zixir repl# Evaluate and get result tuple
Zixir.eval("engine.list_sum([1.0, 2.0, 3.0])")
# => {:ok, 6.0}
# Evaluate and raise on error
Zixir.run("let x = 5\nx * 2")
# => 10
# Direct engine calls (fastest)
Zixir.run_engine(:list_sum, [[1.0, 2.0, 3.0]])
# => 6.0
# Direct Python calls
Zixir.call_python("math", "sqrt", [16.0])
# => 4.0# math_example.zr
let a = 10
let b = 20
let sum = a + b
let product = a * b
engine.list_sum([sum, product])
# Result: 230.0 (30 + 200)
# data_processing.zr
let data = [1.0, 2.0, 3.0, 4.0, 5.0]
let sum = engine.list_sum(data)
let product = engine.list_product(data)
let count = engine.string_count("dataset")
# Return multiple results as array
[sum, product, count]
# Result: [15.0, 120.0, 7]
# python_integration.zr
let numbers = [1.0, 2.0, 3.0, 4.0, 5.0]
# Use Python for advanced math
let mean = python "numpy" "mean" (numbers)
let std = python "numpy" "std" (numbers)
let sqrt_sum = python "math" "sqrt" (engine.list_sum(numbers))
[mean, std, sqrt_sum]
# Result: [3.0, ~1.414, ~3.873]
# string_example.zr
let greeting = "Hello, Zixir!"
let length = engine.string_count(greeting)
let exclamation = "!"
length + engine.string_count(exclamation)
# Result: 16 (15 + 1)
Zixir has a type system that infers types automatically:
# Types are inferred
let x = 42 # Int
let y = 3.14 # Float
let s = "hello" # String
let arr = [1, 2] # [Int]
fn add(x: Int, y: Int) -> Int:
x + y
fn calculate(data: [Float]) -> Float:
engine.list_sum(data) / data.length
let x = 10
let result = if x > 5: "big" else: "small"
| Command | Description | Example |
|---|---|---|
compile |
Compile to native binary | mix zixir compile file.zr |
run |
Compile and execute | mix zixir run file.zr |
check |
Type check only | mix zixir check file.zr |
repl |
Interactive shell | mix zixir repl |
test |
Run tests | mix zixir test |
python |
Test Python FFI | mix zixir python |
| Option | Description | Example |
|---|---|---|
--verbose |
Show detailed output | mix zixir run file.zr --verbose |
--optimize |
Set optimization level | mix zixir compile file.zr --optimize release_fast |
--output |
Set output path | mix zixir compile file.zr --output myapp |
- Use engine operations for math on arrays - they're 100-1000x faster than pure Elixir
- Batch Python calls - minimize Python interop overhead
- Use arrays of floats - engine operations expect
[Float]for best performance - Avoid unnecessary variables - the last expression is automatically returned
# Syntax errors show line and column
let x = # Error: unexpected end of input
# Type errors (when type checking enabled)
let x = "hello"
x + 5 # Error: cannot add String and Int
Install Elixir and add to PATH: https://elixir-lang.org/install.html
Set Python path in config:
config :zixir, :python_path, "/path/to/python"Ensure you ran:
mix deps.get
mix zig.get
mix compileA minimal 2D game that uses the language for position math (via the Zig engine), Elixir for bounce, and Python only for drawing:
mix zixir gameOr: mix run examples/gui_game.exs
- Zixir (language): Each frame we run Zixir source like
engine.list_sum([pos, vel * dt])— your language, not Python expressions. - Zig (engine): That call runs in the Zig NIF (
engine.list_sum), so the hot path is native code, not Python. - Elixir (orchestrator): Handles bounce (flip velocity at walls). Python never sees the math.
- Python/tkinter: Only draws the ball at the positions we send; it does not evaluate Zixir or run the engine.
The game window shows the Zixir snippet and “Zixir + Zig + Elixir → Python” so it’s clear the language and engine are in the loop. Close the window when done.
Because the window is Python/tkinter, it’s easy to think the whole program is Python. In our setup:
- Python’s role: Display only (window, canvas, timer). It does not run your language or the Zig engine.
- Our language’s role: The position each frame is computed by Zixir (
let pos = ... let vel = ... engine.list_sum([pos, vel * dt])) and the Zig engine (the NIF that does the sum). So the language and engine look different (you see the Zixir snippet in the GUI) and perform differently (native Zig in the hot path, not Python). - Elixir’s role: Drives the loop, does bounce logic, and calls Zixir.eval and the Python port. So the “program” is Zixir + Elixir; Python is just the display backend.
To make that visible, the game window displays the Zixir expression and the pipeline (Zixir + Zig + Elixir → Python). For more “language in the foreground” examples, run .zr files with mix zixir run or mix zixir repl and use engine.* in your source so the Zig layer is clearly involved.
Yes. Zixir can be used with SDL2 (or similar native graphics APIs) instead of Python for display.
Right now the GUI examples use Python/tkinter as the display backend. To use SDL2 you'd add it to the project and expose it to the runtime. Typical options:
| Approach | How it works |
|---|---|
| Zig NIFs | Add SDL2 (or a Zig SDL2 wrapper) to the Zig side and expose SDL2 functions as new engine ops or a separate NIF module. Elixir/Zixir then calls e.g. sdl2.init(), sdl2.create_window(), sdl2.render_clear(), etc. Same pattern as the existing engine (Zigler NIFs). |
| Port | Run a separate process (C, Zig, or Rust) that links SDL2 and talks to Elixir over stdin/stdout or a socket. Elixir sends draw commands and receives input events. Similar to the Python port but with a native binary. |
| Elixir SDL2 binding | Use an existing Elixir SDL2 library (if available) and call it from the game loop; Zixir still does the math via Zixir.eval and engine ops. |
In all cases, Zixir and the Zig engine keep doing game math; SDL2 replaces Python as the display and input backend. So: Zixir + Zig (language + engine) + Elixir (loop) + SDL2 (window/rendering/input) instead of + Python/tkinter.
- Language Spec: See
docs/LANGUAGE.md - Examples: Check
examples/directory - Tests: Run
mix testto see working examples - Architecture: See
project_Analysis_for_fork.md
- Try the examples in
examples/directory - Run
mix zixir gameto see the 2D ball game - Run
mix zixir replto experiment interactively - Read the full language specification in
docs/LANGUAGE.md - Check out the test files in
test/for more usage patterns
Happy coding with Zixir! 🚀