콘텐츠로 이동

Python

alpha2 Python 패키지는 alpha2 프로젝트를 만들고, 검사하고, 렌더링합니다. 이 페이지를 읽고 나면 빌더와 작성 헬퍼로 프로젝트를 작성하고, 진행 상황을 받으며 취소도 가능하게 영상 파일로 export하고, 프레임 하나를 PNG로 확인하고, GPU 없이 텍스트를 측정하고, alpha2.compose로 영상 전체를 기술할 수 있습니다.

프로젝트는 엔진의 project.v1 형태를 따르는 평범한 dict이며, 타입은 alpha2.types.Project입니다. 검사는 엔진의 검증기를 같은 프로세스 안에서 그대로 실행합니다. 렌더링은 네이티브 alpha2-host 프로세스가 GPU에서, GPU가 없으면 CPU에서 수행합니다.

터미널 창
pip install alpha2

Linux x86_64·aarch64(glibc 2.35 이상, musl 제외), macOS arm64, Windows x64에서는 같은 버전의 alpha2-host가 플랫폼 휠(alpha2-host)로 함께 설치됩니다. 따로 내려받을 것은 없습니다.

import alpha2
project = alpha2.ProjectBuilder("Intro", width=1280, height=720, frame_rate=30)
title = project.source("image", "title.png")
project.video_track().clip(title, at=0, duration=3)
result = alpha2.export(
project.build(),
"intro.mp4",
assets=project.assets(),
on_progress=lambda p: print(f"{p.completed}/{p.total}"),
)
print(result["output"], result["videoPipeline"], result["frames"])
  • ProjectBuilder(name, width=, height=, frame_rate=, id="project", sample_rate=48000, background=None, ids=None). frame_rate는 int 또는 (num, den) 튜플입니다.
  • source(kind, locator, id=None, has_audio=None)는 video, audio, image 소스를 추가하고 그 id를 반환합니다. 로케이터가 파일 경로이면 assets()가 각 소스 id를 해당 파일에 매핑하며, export에는 이 매핑이 필요합니다.
  • video_track(), audio_track(), caption_track()은 트랙을 추가합니다. clip(source, at=, duration=, source_in=0, source_duration=None, effects=None, ...)은 클립을 배치하며, 그 밖의 키워드 인수로 클립의 다른 필드를 설정할 수 있습니다. 시간은 초 단위 또는 정확한 alpha2.Ticks입니다.
  • build()는 문서를 반환하고, 검사를 통과하지 못하면 예외를 던집니다. alpha2.validate_project(document)는 문제를 문자열 리스트로 반환합니다.

alpha2.export(project, output, **options)는 호스트 프로토콜의 export 필드를 snake_case로 받습니다.

옵션 기본값
assets None {source_id: path}.
start_ticks, end_ticks 0, 프로젝트의 끝 범위. 틱(tick) 단위입니다.
frame_rate 프로젝트의 값 int, (num, den) 튜플 또는 {"num", "den"}.
container 출력 파일 확장자에 따름 mp4, mov, mkv, webm.
video_codec, audio_codec 컨테이너에 따름
video_quality, audio_quality high alpha2.QUALITY_LEVELS의 레벨 하나 또는 {"bitrate": ...}.
include_audio True
alpha, bit_depth False, 코덱에 따름 투명도와 10비트 출력.
loudness None {"target_lufs": -14, "true_peak_ceiling_dbtp": -1}.
fonts, effects, effect_assets None 폴백 순서대로 나열한 폰트 파일, 런타임 이펙트와 그 리소스.
proxies, media, frames, resources 프록시, 이미지 시퀀스, SVG나 Lottie 소스가 참조하는 파일.
render_cache, memory None 렌더링한 프레임 재사용, 바이트 예산.
strategy, input_policy, video_encoder render, auto, None
renderer, video_decode 클라이언트의 값 아래를 참고하세요.
overwrite False export가 완전히 끝난 뒤 기존 파일을 교체합니다.
on_progress, cancel None 콜백과 threading.Event.

직접 쓰는 옵션은 snake_case이고, 호스트가 보고하는 값은 프로토콜의 camelCase 키를 그대로 씁니다(result["effectiveRange"]).

  • output이 이미 있으면 overwrite=True를 넘기지 않는 한 거부됩니다. export의 입력 파일 중 하나를 출력으로 지정하면 항상 거부됩니다.
  • on_progress는 phase(frames 또는 finalizing), completed, total을 담은 ExportProgress를 받습니다.

cancel 이벤트를 설정하거나 Ctrl-C를 누릅니다. 클라이언트가 취소 줄을 쓰면 호스트는 export를 멈추고, 부분 출력 파일을 지우고, 응답한 뒤 종료합니다. 이 모든 일이 호출이 반환되기 전에 끝납니다.

import threading
cancel = threading.Event()
threading.Timer(10, cancel.set).start() # 10초 뒤에 포기합니다
try:
alpha2.export(document, "long.mp4", assets=assets, cancel=cancel)
except alpha2.Alpha2AbortError:
print("cancelled")

5초 안에 응답하지 않는 호스트는 강제로 종료되며, Ctrl-C를 한 번 더 누르면 즉시 종료됩니다. 호스트를 시작한 프로세스가 죽으면 호스트도 함께 종료됩니다.

alpha2.export, alpha2.still, alpha2.conform, alpha2.capabilities는 공유 HostClient 위에서 실행됩니다. 동시 실행 수를 제한하거나 작업을 분리하려면 클라이언트를 직접 만듭니다.

client = alpha2.HostClient(concurrency=2, renderer="auto", host_start_timeout=30.0)
client.export(document, "a.mp4", assets=assets)

concurrency는 클라이언트가 동시에 실행하는 호스트 프로세스 수입니다.

문서는 평범한 dict이고, 헬퍼는 값, 이펙트, 클립의 visual, 레이아웃, 셰이프를 dict로 써 줍니다. 헬퍼는 문서의 필드 이름을 그대로 쓰므로 헬퍼와 직접 작성한 dict를 자유롭게 섞을 수 있습니다.

import alpha2
from alpha2 import effect, key, keyframes, visual
from alpha2.layout import box, layout, text
from alpha2.shapes import circle, fill, shapes
project = alpha2.ProjectBuilder("Card", width=1280, height=720, frame_rate=30)
card = project.generated(
layout(
box(
text("Hello", font_size="40px", line_height=1.4),
padding="12px 20px",
background="#1e2230",
border_radius="16px",
)
)
)
project.video_track().clip(
card,
at=0,
duration=3,
visual=visual(opacity=keyframes(key(0, 0.0), key(0.5, 1.0)), scale=1.2),
effects=[effect("alpha2.effect.gaussian-blur", radius=0.002)],
)
dot = project.generated(shapes(circle((0.5, 0.5), 0.2, picture=(1280, 720)), fill("#ffb020")))
project.video_track().clip(dot, at=0, duration=3)
document = project.build()
assert alpha2.validate_project(document) == []
  • key(at, value)의 at은 초 단위 또는 alpha2.Ticks입니다. keyframes(*keys)는 순서가 어긋난 키를 정렬하지 않고 거부합니다. 그 밖의 필드는 일반 값을 받으며, 이 값은 상수가 됩니다. 애니메이션을 참고하세요.
  • effect(id, **params)는 이펙트를 추가합니다. effect가 내부에서 쓰는 fx.param은 float, bool, (x, y) 쌍, 16진수 색상을 파라미터 값으로 바꿉니다. int나 4-튜플은 모호하므로 TypeError를 던지며, 대신 쓸 생성자(fx.scalar(1.0) 또는 fx.enum(1), fx.vec4 또는 fx.color)를 알려 줍니다.
  • alpha2.layout은 TypeScript alpha2/layout과 같은 빌더입니다. box(*children, **props), text(content, **props), shape(items, **props)를 제공합니다. 레이아웃을 참고하세요.
  • alpha2.shapes는 셰이프 제너레이터를 그립니다. shapes(*items), circle, fill 등이 있습니다. 제너레이터를 참고하세요.
대상 단위
위치: 클립의 position과 anchor, 셰이프의 center, 패스 꼭짓점 축별: x는 너비에 대한 비율, y는 높이에 대한 비율
셰이프(rect, ellipse)의 크기 위치와 같이 축별: (0.5, 0.5)는 정사각형 화면에서만 원이 됩니다
길이: 모서리 반지름, 선 두께, 대시, 블러 반지름, 레이아웃 숫자 화면 짧은 변에 대한 비율
폰트 크기(텍스트 제너레이터, 레이아웃) 화면 짧은 변에 대한 비율, 또는 레이아웃에서는 캔버스 기준 "40px"
자간, 텍스트 외곽선 두께, 텍스트 그림자 오프셋과 블러 폰트 크기에 대한 비율

circle(center, diameter, picture=(w, h))는 둥근 타원을 만듭니다. 지름은 짧은 변에 대한 비율이고, picture는 셰이프가 그려지는 화면의 크기이므로 기본값이 없습니다.

소유자 키프레임 시간 기준
클립의 visual, 클립의 마스크, 트랜지션 타임라인 시간(프로젝트 시작부터)
컴포지션 설정(클립의 effects) 컴포지션 시간(클립 시작부터)
셰이프·레이아웃 제너레이터 화면 시간: 클립이 선택한 소스 시간

키프레임을 잘못된 기준으로 쓰면 대개 그 소유자가 화면에 보이는 시간 밖에 놓입니다. alpha2.lint_project(document)는 어떤 프레임도 도달하지 않는 키프레임을 unreached_keyframe으로 보고하며, 소유자와 속성, 시간을 함께 알려 줍니다.

레이아웃 text는 문자열 키프레임을 받으므로, 카운트업도 클립 하나로 만들 수 있습니다.

count = keyframes(*(key(i / 30, str(i)) for i in range(101)))
counter = project.generated(layout(box(text(count, font_size=0.2), justify_content="center")))

텍스트는 한 키에서 다음 키까지 값을 유지합니다. text는 key의 기본값인 linear를 hold로 기록하며, 그 밖의 보간은 거부합니다.

alpha2.still은 영상을 인코딩하지 않고, export가 그 시점에 그릴 프레임 하나를 PNG로 렌더링합니다.

result = alpha2.still(project.build(), 1.5, "check.png", assets=project.assets())
print(result["stills"][0]["frameTime"]) # 1.5초를 포함하는 그리드 프레임의 시간(틱 단위)
  • 시간은 초 단위 또는 정확한 alpha2.Ticks입니다. 그려지는 프레임은 프로젝트의 프레임 그리드에서 그 시간을 포함하는 프레임입니다.
  • alpha2.stills(project, [(0, "a.png"), (2.5, "b.png")], ...)는 호스트 하나로 최대 256개 프레임을 렌더링하며, 디코딩은 한 번만 합니다. size=(width, height)로 다른 캔버스 크기로 렌더링할 수 있고, alpha=True는 배경 없이 그립니다.
  • PNG는 8비트 RGBA이며, 비디오 인코딩을 거치기 전의 화면입니다.

alpha2.TextMeasurer(fonts)는 엔진의 배치 코드를 그대로 사용해 GPU 없이 텍스트와 레이아웃 제너레이터를 측정합니다. export에 넘기는 폰트 파일을 같은 순서로 넘기세요.

measurer = alpha2.TextMeasurer(["fonts/Inter.ttc"])
bounds = measurer.layout(card_layout, picture=(1280, 720))
title = bounds["nodes"][1]
print(title["border"], title["lineCount"], title["overflow"], title["baselines"])
words = measurer.text({"type": "text", "text": "Hi"}, canvas=(1280, 720))

사각형은 화면에 대한 비율로, 왼쪽 위 (0, 0)부터 오른쪽 아래 (1, 1)까지입니다. 화면이 실제로 그려지는 크기에서 측정하세요. 크기가 다르면 줄바꿈 위치가 달라질 수 있습니다. 측정기는 폰트를 한 번만 읽고 측정하는 동안 GIL을 해제하므로, 텍스트가 맞을 때까지 크기를 줄여 가는 루프도 빠르게 돕니다.

alpha2.compose는 영상을 무엇으로 이루어졌는지로 기술하고, 이를 프로젝트로 컴파일합니다. 시간은 초, 길이는 캔버스 픽셀, 파일은 경로로 씁니다. 컴파일 결과에는 에셋, 폰트, 라우드니스가 담겨 alpha2.export로 전달됩니다.

from pathlib import Path
import alpha2
from alpha2 import compose as c
video = c.Video(
canvas="youtube-1080p",
body=c.Slideshow(
sorted(Path("photos").glob("*.jpg")), seconds=6, transition=c.Crossfade(1), ken_burns=1.15
),
overlays=[c.Title("Summer 2026", at=0.5, duration=4)],
audio=c.MusicBed("music.m4a", fade_out=3),
)
compiled = video.compile(fonts=["DejaVuSans-Bold.ttf"]) # compiled.project는 평범한 dict입니다
alpha2.export(compiled, "summer.mp4")
  • 노드: Sequence, Stack, Grid, Media, Text, Color, Captions(SubRip, WebVTT, 큐 또는 단어별 타임스탬프), Layout, Audio, Raw(프로젝트의 일부를 오버레이로 넣음).
  • 컴포넌트: Slideshow, CaptionedVideo, Title, TitleCard, LowerThird, EndCard, ComparisonGrid, Reframe, Logo, MusicBed.
  • 테마: clean-dark와 clean-light, 또는 직접 만든 테마(theme={"base": "clean-light", "accent": "#e63946"}).
  • 컴파일하려면 각 파일의 크기와 길이가 필요합니다. compile은 이를 호스트의 conform에 묻거나(GPU 불필요), facts=로 받습니다. 미디어 파일이 없는 영상은 호스트 없이 컴파일됩니다. 같은 스펙, facts, 폰트는 같은 프로젝트로 컴파일됩니다.
  • 스펙은 JSON이며(video.to_json(), 타입은 alpha2.compose_types.VideoSpec), compose 스키마가 이를 정의합니다. 모든 바인딩이 이를 똑같이 컴파일합니다.
  • 오류는 스펙의 어느 위치에서 났는지 알려 줍니다. 예를 들어 alpha2.Alpha2ComposeError의 .path == "spec.body.items[3].path"입니다.

renderer=("auto", "gpu", "cpu")는 프레임을 무엇으로 그릴지, video_decode=("software", "auto", "hardware-required")는 비디오를 어떻게 디코딩할지 정합니다. HostClient(...)에 설정하면 모든 요청에 적용되고, export, still, capabilities 호출마다 따로 지정할 수도 있습니다. 지정하지 않으면 호스트는 ALPHA2_RENDERER와 ALPHA2_VIDEO_DECODE를 읽고, 그것도 없으면 렌더러는 auto, 디코딩은 Linux와 macOS에서 auto, Windows에서 software를 씁니다.

  • auto는 하드웨어 GPU가 있으면 그 위에서, 없으면 CPU에서 렌더링하며, 소프트웨어 GPU 어댑터는 쓰지 않습니다. gpu는 찾은 어댑터를 무엇이든 사용하며, 어댑터가 없으면 GPU_INIT_FAILED로 실패합니다. cpu는 그래픽 드라이버를 열지 않습니다.
  • 결과와 capabilities는 renderer, rendererReason, 그리고 CPU에서는 rendererThreads를 보고합니다. 런타임 WGSL 이펙트는 CPU 렌더러에서 실행할 수 없으므로, 그런 export는 EFFECT_ERROR로 실패합니다.
  • auto 디코딩에서 하드웨어 디코더가 멈춘 export는 소프트웨어 디코딩으로 한 번 더 실행됩니다.

모든 실패는 alpha2.Alpha2HostError이며, 기계가 읽을 수 있는 code와 재시도 정책에 쓸 분류된 failure dict를 담고 있습니다. 하위 클래스로 Alpha2ProjectValidationError, Alpha2ConformError, Alpha2GpuInitializationError, Alpha2AbortError가 있습니다.

  • host_start_timeout(초 단위, HostClient 인수, 기본값 30, None이면 무한정 대기) 안에 아무것도 쓰지 않는 호스트는 HOST_START_TIMEOUT으로 강제 종료됩니다.
  • macOS가 격리(quarantine)한 호스트는 시작 전에 HOST_QUARANTINED로 거부됩니다. Windows가 정책으로 차단한 호스트는 HOST_BLOCKED입니다. 프로그램 인터프리터가 없거나(musl) glibc가 너무 오래된 Linux 호스트는 HOST_LOAD_FAILED입니다.

python -m alpha2는 같은 작업을 명령으로 제공합니다.

터미널 창
python -m alpha2 export project.json out.mp4 --asset title=title.png --video-quality high
python -m alpha2 still project.json check.png --at 1.5 --asset title=title.png
python -m alpha2 capabilities
python -m alpha2 install # alpha2-host를 공유 캐시에 내려받습니다
python -m alpha2 install --openh264 # 소프트웨어 H.264용 Cisco OpenH264

클라이언트는 host_path 인수, ALPHA2_HOST_PATH, 이 버전의 alpha2-host 휠, 공유 캐시에 있는 이 버전의 아카이브, PATH 순서로 찾습니다.

python -m alpha2 install은 @alpha2-sh/node도 쓰는 캐시(ALPHA2_HOST_CACHE_DIR, 없으면 ~/.cache/alpha2, ~/Library/Caches/alpha2 또는 %LOCALAPPDATA%\alpha2)에 릴리스 아카이브를 내려받으므로, 한 번 내려받은 것을 양쪽에서 함께 씁니다. 아카이브는 배포된 휠에 고정된 SHA-256으로 검증합니다. 고정값이 없는 소스 체크아웃에서는 릴리스의 checksums.sha256으로 검증합니다(어느 쪽인지는 InstallResult.verified_by가 알려 줍니다). 코드에서는 alpha2.install_host()가 같은 일을 합니다.

다운로드는 HTTPS_PROXY와 NO_PROXY를 따릅니다. ALPHA2_HOST_DOWNLOAD_URL(또는 download_url 인수)로 https://github.com/alpha2-sh/alpha2/releases/download와 같은 구조의 미러를 지정할 수 있습니다.