Status: Proof of Concept. This repository is a POC that proved the foundations — Arabic rendering in an isolated container and the plan→template→render spine. It is not the end product. The post-POC product direction lives in
docs/PRODUCT_DIRECTION.md.
Bayan is an Arabic AI-powered video generator built on top of Manim.
This project targets Manim Community Edition. It installs the Community
Edition package as manim (version 0.20.1 or newer), rather than the legacy
manimlib package.
Before running the project, install the system-level dependencies required by Manim for rendering shapes, text, and compiling audio:
reshape_arabic_textreshapes Arabic ligatures and applies the BiDi algorithm before rendering.ArabicTextprovides a Manim text object withNoto Sans Arabicas its default font.rtl_glyphsexposes glyphs in visual right-to-left order for animation.ArabicSanityCheckrenders a small integration scene so Arabic connections, direction, and glyph animation can be checked visually.- A container smoke runner builds a digest-pinned, multi-stage render image, runs the Arabic sanity scene without network access, validates its artifacts, and saves a video, preview, log, and typed manifest.
- Python 3.11 or newer
uv- Docker Engine or Docker Desktop for the isolated smoke render
- FFmpeg, Cairo, and Pango, which Manim uses for rendering
Noto Sans Arabicor another font with Arabic glyph coverage- LaTeX only if you need to render mathematical equations with LaTeX
On Ubuntu or Debian:
sudo apt update
sudo apt install -y ffmpeg build-essential pkg-config python3-dev \
libcairo2-dev libpango1.0-dev fonts-noto-coreThe sanity scene uses Noto Sans Arabic for predictable Arabic glyph coverage.
The fonts-noto-core package provides it on Ubuntu/Debian.
choco install ffmpeg pango cairo -yIf this is your first time using the project, follow these steps in order. You
do not need to activate a virtual environment manually: uv run uses the
project's .venv automatically.
-
Install
uv(skip this step ifuv --versionalready works):macOS/Linux:
curl -LsSf https://astral.sh/uv/install.sh | shWindows PowerShell:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
Close and reopen your terminal after installing
uv, then check it:uv --version
-
Install the Python dependencies and create the project environment:
uv sync
This creates
.venvand installs the versions recorded inuv.lock. -
Confirm the Manim edition and version:
uv run manim --version # Manim Community v0.20.1 (or newer) -
Run the Arabic rendering check:
uv run manim -ql bayan/utils/sanity_check.py ArabicSanityCheck
The
-qloption means “quick, low quality,” so this check finishes faster than a final render. A successful run creates a video undermedia/videos/. -
Run the tests (optional):
uv run pytest
bayan reads its LLM settings from the environment (a local .env file is
loaded automatically and must never be committed). The resolution order is:
explicit CLI argument, then the BAYAN_* variable, then the fallback.
| Variable | Purpose | Default |
|---|---|---|
BAYAN_API_KEY |
API key for the OpenAI-compatible provider. Required unless OPENAI_API_KEY is set. |
none |
OPENAI_API_KEY |
Fallback API key when BAYAN_API_KEY is unset. |
none |
BAYAN_BASE_URL |
OpenAI-compatible API endpoint. | https://api.z.ai/api/coding/paas/v4/ |
BAYAN_LLM_MODEL |
Model name sent with every request. | glm-5.2 |
Copy .env.example to .env and fill in your key. Follow the key-safety
guidance at
Best practices for API key safety:
keys never belong in source code, error messages, logs, or run records, and
Bayan redacts the resolved key from every error it raises.
uv run manim --version
uv run manim -ql bayan/utils/sanity_check.py ArabicSanityCheckThe render should create a video under media/videos/. Visually confirm that
Arabic letters are connected, text flows from right to left, and glyphs animate
in the expected order.
Build the render image and run the same Arabic scene in a container with no network access:
uv run python scripts/container_smoke.pyThe command creates a fresh directory under artifacts/container-smoke/ for
each run. It does not delete earlier runs. Each run contains draft.mp4,
preview.png, render.log, smoke_manifest.json, and the raw Manim output.
The manifest records the image ID, source hashes, resource policy, phase
statuses, and relative output paths. Worker output is capped per phase so a
broken scene cannot fill the host disk.
The worker has no network, runs as a non-root user, mounts the scene read-only,
and writes only to the dedicated run output directory. The Docker CLI itself
receives an allowlisted environment; host application secrets are not passed
to the worker. Use --skip-build only when you intentionally want to test an
already-built local image.
On an ephemeral builder — CI runners or Google Cloud Build — the Docker layer cache starts empty, so every build would rebuild the image from scratch. Pass a previously pushed image as the cache seed to reuse its layers:
uv run python scripts/container_smoke.py --cache-from ghcr.io/acme/bayan-cache:cacheThe option is repeatable and recorded in smoke_manifest.json
(settings.build_cache_from). CI applies the full loop: pull the cached
image, build with --cache-from, then push the freshly built image back to
the cache tag so the next build starts warm.
If Docker is installed but its daemon is not running, start Docker and run the
command again. If the command fails, read smoke_manifest.json and
render.log before retrying.
Run the same checks used by the project’s development tooling:
uv run ruff check .
uv run ruff format --check .
uv run mypy bayan
uv run pytest
uv run pre-commit run --all-filesIf uv sync fails in Meson while building pycairo, verify that Cairo is
discoverable through pkg-config:
pkg-config --modversion cairoIf that command cannot find Cairo, install the native dependencies for your
platform and run uv sync again.
CONTEXT.md Canonical domain vocabulary
bayan/
├── renderer/
│ ├── docker.py Bounded Docker lifecycle and security policy
│ ├── models.py Typed render settings and manifest models
│ └── smoke.py Arabic smoke-run orchestration and validation
└── utils/
├── arabic_helper.py Arabic shaping, RTL text, and glyph helpers
└── sanity_check.py Render-level Arabic integration scene
Dockerfile Pinned container for the Arabic smoke render
scripts/container_smoke.py Thin CLI for the bounded container smoke run
container/
├── pyproject.toml Render-only dependency declarations
└── uv.lock Locked render dependency graph
docs/
├── PRODUCT_DIRECTION.md Post-POC product direction (current)
├── PROJECT_NORTH_STAR.md POC strategy and success signals
├── ARCHITECTURE.md Target system boundaries
├── DOMAIN_MODEL.md Domain relationships and invariants
├── DEVELOPMENT.md Contributor development loop
├── reference/ Terminology references
│ └── manim-glossary.md Shared Manim vocabulary
├── research/ Product research notes
│ ├── educator-study-plan.md
│ └── probe-storyboard-circle-area.md
└── agdr/ Architecture and developer decisions
├── AgDR-0001-type-checker.md
└── AgDR-0002-render-isolation.md
.agents/
└── skills/
└── manim-video/ Project-scoped Manim video skill
tests/
├── test_arabic_helper.py Arabic shaping and glyph-order tests
└── test_smoke.py Package import smoke tests
main.py Current application entry-point placeholder
The Manim video skill under .agents/skills/manim-video/ is intentionally
project-scoped and versioned with this repository. Keep it available to
contributors working on Bayan; it should not be replaced by a global skill
installation.
The repository is intentionally small today. As the product grows, keep the workflow separated into explicit boundaries:
- Content domain — structured lessons, scene plans, and render metadata.
- Generation — deterministic or model-assisted production of a constrained scene representation.
- Rendering — isolated execution of Manim scenes and collection of output artifacts.
- Validation — Arabic RTL checks, visual smoke checks, mathematical or content validation, and safety checks for generated code.
- Interfaces — a CLI or API that composes the workflow without owning the domain rules.
The key architectural rule is to keep domain logic independent of Manim. Scene files should be thin rendering adapters, while generated code should run in an isolated process rather than inside the application host.
See the detailed architecture and domain model. The current product direction is in PRODUCT_DIRECTION.md; PROJECT_NORTH_STAR.md is scoped to the POC strategy and success signals.
The docs/agdr/ directory records decisions that affect the project’s
architecture and development workflow. Start with
AgDR-0001-type-checker.md to understand
the mypy boundary around Manim scenes. The accepted render-isolation boundary is
recorded in AgDR-0002-render-isolation.md.
- Package Manager:
uv(PEP 621 & PEP 735) - Linter & Formatter:
ruff - Testing:
pytest