CodeAnim
中文说明 · English
Describe animation in Python code. One command renders it to a video file. No window, no interaction, no player — it just writes the file and exits.
codeanim examples/demo.py
# -> out.mp4
Zero-disk by default. Frames are piped straight into ffmpeg's stdin; no temporary files are written along the way. Disk usage equals the final video size, so 4K / high-quality / long clips are safe to run.
Contents
- Install
- Command line
- Hot reload
- In-terminal preview
- Drawn primitives
- Gradients / shadows / 3D tilt
- Particles
- Text
- Images & sprite animation
- Audio
- Composing a scene
- Disk safety
- Output formats
- Design constraints
- Testing
- Examples
Install
Needs Python 3.8+, Pillow, and ffmpeg.
pip install codeanim-py # "-py" suffix: `codeanim` was taken on PyPI
codeanim doctor # checks the dependencies, tells you what to install
The import name is still
codeanim— you never type the distribution name in your code:from codeanim import Scene # not codeanim_py
Language
Output is English by default. Add --ch for Chinese:
codeanim demo.py # English help / logs / errors
codeanim demo.py --ch # 全程中文
codeanim demo.py --zh # same thing
CODEANIM_LANG=zh codeanim demo.py # or via env var
This affects the CLI help, progress, warnings, and error messages. Docstrings and comments in the source stay Chinese.
Not installing is also fine (handy when working on the engine itself):
python -m pip install -r requirements.txt
python main.py doctor
Command line
codeanim <script.py> [options]
codeanim doctor
| Option | What it does | Default |
|---|---|---|
-o, --output |
Output path; extension picks the format | out.mp4 |
--fps |
Frame rate | 30 |
--quality |
low / medium / high / lossless |
high |
--workers, -w |
Parallel processes | CPU cores − 1 |
--snapshot <sec> |
Render a single PNG frame | — |
--frames <dir> |
Export a PNG sequence | — |
--gif |
Export GIF | — |
--keep-frames |
Keep intermediate frames (debug) | off |
--supersample <n> |
Supersampling factor | 2 |
--mode <m> |
Frame storage: stream / ram / disk |
auto |
--alpha |
Keep alpha channel (.mov / .webm) |
auto |
--ffmpeg <path> |
Path to ffmpeg | ffmpeg |
--watch, -W |
Hot reload on file change | off |
--watch-at <sec> |
Preview time point for --watch |
0 |
--inline |
Draw the frame in the terminal | auto |
--no-inline |
Don't draw in-terminal | — |
--preview <sec> |
Render one frame and open it | — |
--no-audio |
Ignore audio tracks | off |
--list-audio |
List the audio tracks and exit | — |
--layers |
Print the draw order and exit | — |
--ch / --zh / --en |
Output language | en |
--quiet, -q |
Only print errors | off |
--free-margin <size> |
Abort below this much free disk | 256MB |
--force |
Render even if disk-space check fails | off |
--no-disk-check |
Skip all disk checks | off |
codeanim demo.py --watch # edit with live preview
codeanim demo.py --watch --watch-at 2.5 # watch one specific frame
codeanim demo.py --preview 2.0 # one frame, then open it
codeanim demo.py --snapshot 2.0 # one frame, don't open
codeanim demo.py --gif # GIF
codeanim demo.py --frames pngs/ # PNG sequence
codeanim demo.py -o out.mov --alpha # transparent MOV
codeanim demo.py --layers # who covers whom
codeanim demo.py --list-audio # the audio timeline
Hot reload
The slow loop when writing animation is edit → run → wait → open the file.
--watch removes everything in the middle:
codeanim examples/demo.py --watch
CodeAnim hot reload
────────────────────────────────────────────────────────
entry examples/demo.py
watching 7 .py files
preview .codeanim/watch_preview.png
t = 2.00s
────────────────────────────────────────────────────────
Save a file and the preview refreshes. Ctrl-C to quit.
✓ updated 1280x720 8.60s 30 fps 11 primitives
preview .codeanim/watch_preview.png (t=2.00s)
took 814 ms
↻ changed: examples/demo.py
✓ updated 1280x720 8.60s 30 fps 11 primitives
took 225 ms
- Watches the entry script and every project
.pyit imports — editing a fragment file triggers it too - Renders one frame, not the whole video — typically 200–800 ms
- Errors don't exit: syntax / runtime errors are printed, then it keeps waiting
- Editor "save" bursts are debounced into a single re-render
- Newly added
.pyfiles are picked up automatically - No third-party deps, plain mtime polling, cross-platform
In-terminal preview
Don't want to open an image? Draw it right in the terminal:
codeanim examples/demo.py --watch --inline
✓ updated 1280x720 8.60s 30 fps 11 primitives took 1.46 s
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▄▄▄ CodeAnim animation in Python ▄▄▄
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
● ●
t=4.00s 11 primitives .codeanim/watch_preview.png
A terminal cell is roughly 1:2 (width:height), so the upper/lower half block
▄ lets one cell carry two vertical pixels and keeps the aspect ratio honest.
An 80×24 terminal is about 80×48 colour cells — enough for layout, palette,
and placement.
- True colour (24-bit) first, then 256 colour, then greyscale characters
- Repaints in place (ANSI cursor movement), no scrolling
- Auto-detects terminal support;
--no-inlinedisables,--inlineforces - Also callable from code:
from codeanim import render_terminal_preview, preview_lines
print(render_terminal_preview(scene, at=2.0)) # a coloured string
lines = preview_lines(scene, at=2.0, max_cols=80) # list of lines
Drawn primitives
| Primitive | Position anchor | Main options |
|---|---|---|
Circle |
centre | r, fill, stroke, stroke_width |
Rect |
top-left | w, h, radius, fill, stroke |
Line |
start point | stroke, stroke_width |
Text |
by anchor |
text, font_size, anchor, fill, fit_width |
Image |
top-left | source, w, h, crop, slice, tint, radius |
Path |
top-left | points, spline, closed, progress, arrow, dash |
Digits |
by anchor |
value, decimals, thousands, formatter |
Group |
centre | rotation, scale, opacity |
Origin is top-left, y grows downward.
Every primitive also accepts:
| Option | Meaning |
|---|---|
cx / cy |
position by geometric centre (no manual offset math) |
z |
layer number, higher draws on top |
rotation / scale / opacity |
transforms, all animatable |
shadow |
drop shadow (see below) |
perspective |
3D-ish tilt (see below) |
Anything numeric or colour can be keyframed:
ball.cx.keys([(0, 200), (2, 1000)]) # centre over time
ball.fill.keys([(0, "red"), (2, "#00aaff")]) # colour interpolation
ball.x.keys([(0, 0), (1, 500)], ease="outBack") # ease per segment
25 built-in easing curves (linear, inOutCubic, outBack, inOutElastic,
outBounce, …). ease= goes on the starting keyframe and describes the
segment toward the next one.
Layer order
codeanim script.py --layers # who covers whom
codeanim script.py --layers --layers-at 2.5
Draw order (bottom to top, 30 items)
────────────────────────────────────────────────────────────────────────
# z type name position / size
────────────────────────────────────────────────────────────────────────
1 -100 rect <rect> (0,0) 1280x720
2 0 text <text> c(640,340) 'one command, one video'
3 10 text <text> c(640,330) 'CodeAnim'
4 20 digits <digits> c(1220,650) '0,000 frames'
────────────────────────────────────────────────────────────────────────
! Some primitives share the same z: 0(25), 10(3).
Same z draws in insertion order -- later ones on top.
! 1 static primitive(s) get pre-composed into the bottom layer.
It warns about: all-equal z, duplicated z, static primitives (they get
baked into a bottom layer), and decreasing z (usually group mixing).
Gradients / shadows / 3D tilt
from codeanim import Gradient, Shadow, Perspective
# gradient fill — just pass it as `fill=`
box = Rect(cx=640, cy=360, w=400, h=200,
fill=Gradient.linear("#38bdf8", "#a855f7", angle=45))
Circle(cx=200, cy=200, r=80, fill=Gradient.radial("#fff", "#f00"))
Circle(cx=500, cy=200, r=80, fill=Gradient.conic(["#f00", "#0f0", "#00f"]))
# uneven stops
Gradient.linear([(0.0, "#000"), (0.3, "#38bdf8"), (1.0, "#fff")])
# drop shadow
card = Rect(cx=640, cy=360, w=300, h=180, fill="#1e293b",
shadow=Shadow(blur=20, dy=8, alpha=0.5))
# 3D-ish tilt (quad warp, not real 3D — still pure & parallel)
panel = Rect(cx=640, cy=360, w=400, h=300, fill="#0ea5e9",
perspective=Perspective(tilt_y=25, tilt_x=-10, distance=900))
| Gradient | |
|---|---|
linear(*stops, angle=90) |
0° = left→right, 90° = top→bottom |
radial(*stops, center=(.5,.5), radius=.5) |
centre → edge |
conic(*stops, angle=0) |
sweep around, good for rainbows / progress rings |
| Shadow | |
|---|---|
dx / dy |
offset in pixels |
blur |
gaussian radius, 0 = hard edge |
alpha |
opacity 0–1 |
spread |
grow the shape before blurring |
color |
default black |
| Perspective | |
|---|---|
tilt_x |
pitch, in degrees |
tilt_y |
yaw, in degrees |
rotate |
in-plane rotation |
distance |
camera distance; smaller = stronger |
The output canvas is sized to the projected quad only. That's what makes the narrowing actually visible — if it kept the original size the content would just stretch back.
Particles
Particles are not a renderer special case. emit() bakes each particle's
motion into keyframes, so scenes stay pure, seekable, and parallel-safe.
from codeanim import emit, emit_snow, emit_sparkle, emit_ripple
# one burst
emit(scene, count=120, at=(640, 360), t0=1.0,
velocity=(200, 0), spread=260, gravity=500,
life=1.8, r=(2, 6), fill=["#38bdf8", "#a855f7", "#f472b6"])
# a fountain
emit(scene, count=60, at=(640, 700), t0=0.0, t1=3.0,
velocity=(0, -420), spread=90, gravity=380, life=2.0, r=4)
# one-liners
emit_snow(scene, count=80) # snowfall with sway
emit_sparkle(scene, count=40) # twinkle in place
emit_ripple(scene, count=3) # expanding rings
emit option |
|
|---|---|
count |
how many |
at |
(x, y), or ((x1,y1),(x2,y2)) for a spawn rectangle |
t0 / t1 |
start time / end time (t1 = continuous emission) |
velocity + spread |
initial velocity and its random range |
angle=(centre, cone) |
cone emission in degrees |
gravity / drag |
acceleration / air resistance |
life, r |
single value or (min, max) |
fill |
a colour or a list to pick from |
seed |
reproducible — same seed, same result every render |
max_particles |
safety cap (default 600), exceeded = loud error |
Text
from codeanim import Text
Text("Hello", cx=640, cy=360, font_size=48, fill="white", anchor="center")
# auto-shrink to fit a width (or height)
Text("A very long headline that must not overflow",
cx=640, cy=120, font_size=96, fit_width=900, anchor="center")
# multi-line — "\n" splits, line_height scales the leading
Text("line one\nline two\nline three",
cx=640, cy=360, font_size=36, line_height=1.4, anchor="center")
# change the copy in place, no rebuild
t = scene.add_text("old title", cx=640, cy=100)
t.set_text("new title")
t.content = "or assign it"
fit_width / fit_height binary-search the font size at render time;
font_size itself is unchanged, so you can animate it independently and they
compose.
anchor accepts center / left / right / top / bottom and the usual
combinations (top_left, bottom_right, …).
Images & sprite animation
from codeanim import Image, load_image, load_or_placeholder
logo = scene.add_image("logo.png", cx=640, cy=360, w=200, radius=16)
logo.rotation.keys([(0, 0), (2, 360)])
scene.add_image("hero.png", cx=300, cy=200, w=240) # h from aspect
tex = load_image("icon.png") # load once, reuse
scene.add_image(tex, cx=200, cy=500, w=80)
scene.add_image(tex, cx=320, cy=500, w=80, tint="#22d3ee")
scene.add_image(None, cx=100, cy=100, w=60, h=60) # checkerboard stub
| Option | |
|---|---|
w / h |
give one, the other follows the aspect ratio |
crop=(x,y,w,h) |
cut a rect out of the source (sprite sheets) |
slice= |
9-slice: 12 or (l,t,r,b) — corners don't distort |
radius= |
rounded corners |
tint= + tint_amount= |
colourise, good for monochrome icons |
fit= |
stretch (default) / contain / cover |
Sprite animation
sheet = scene.add_image("run.png", sprite=(4, 3), w=96)
sheet.play(fps=12) # loop at 12 fps
sheet.show_frame(0, at=2.0) # pin a frame
# reverse / manual stepping via keyframes
sheet.frame.keys([(0, 11), (2.6, 0)])
# or slice manually
scene.add_image("run.png", frames=[(0,0,48,48), (48,0,48,48)], w=48)
Audio
Two things only: import a file and say when it plays, or generate a sound in code. Deliberately plain — no node graph, no automation curves.
from codeanim import Audio, beep, chime, sweep, whoosh, arpeggio
# --- import ---
scene.add_audio(Audio("bgm.mp3", at=0.0, volume=0.35,
loop=True, fade_in=0.5, fade_out=2.0))
scene.add_audio(Audio("whoosh.wav", at=3.5))
scene.add_audio(Audio("speech.mp3", at=2.0, trim=(3.0, 8.0)))
# --- generate (no assets needed) ---
scene.add_audio(beep(880, duration=0.2, at=1.0))
scene.add_audio(chime(at=5.0))
scene.add_audio(whoosh(at=2.6))
scene.add_audio(sweep(200, 1600, duration=0.35, at=3.0))
scene.add_audio(arpeggio([523, 587, 659, 784], at=7.4))
Audio option |
|
|---|---|
at |
when it starts, in absolute seconds (ms precision) |
volume |
gain multiplier |
loop |
loop to fill the rest |
fade_in / fade_out |
seconds |
trim=(start, end) |
take a slice of the source |
speed |
playback rate (also shifts pitch) |
volume_curve |
automation, see below |
pan |
-1 left … 0 centre … +1 right |
delay |
echo: seconds / (delay, decay) / (delay, decay, count) |
reverb |
0–1, larger = roomier |
tone |
brightness, negative = duller |
Music notation
Stop typing frequencies:
from codeanim import note, chord, scale, melody, parse_melody
note("A4") # -> 440.0
note("C#5") / note("Db5") # sharps / flats
chord("A3", "m7") # 19 chord types
scale("C4", "blues") # 14 scales
parse_melody("1 2 3 4 5") # numbered notation
parse_melody("1' 2'") # up an octave
parse_melody("1, 2,") # down an octave
parse_melody("1 2 3", solfege_key="G") # in G
Write a melody:
scene.add_audio(melody("C4 D4 E4 F4 G4", note_dur=0.2, at=0.0))
scene.add_audio(melody("1 2 3 4 5 6 7 1'", note_dur=0.18))
scene.add_audio(melody([["C4","E4","G4"], ["F4","A4","C5"]], note_dur=0.8))
scene.add_audio(chord_sound("C4", "maj", duration=1.5, at=0.0))
Voices & envelopes
from codeanim import Tone, Envelope, VOICES
Tone(freq=note("C4"), duration=1.5, voice="epiano")
Tone(freq=note("C5"), duration=2.0, voice="bell", reverb=0.6)
Tone(freq=note("E4"), duration=1.0, voice="strings", vibrato=(5, 25))
# ADSR: attack / decay / sustain / release
Tone(freq=note("C4"), duration=1.5, voice="epiano",
envelope=Envelope(attack=0.01, decay=0.25, sustain=0.45, release=0.5))
Tone(freq=440, duration=1.0, envelope=(0.01, 0.2, 0.5, 0.4)) # tuple works too
| Voice | Sounds like |
|---|---|
sine square triangle saw |
basic waveforms |
flute |
flute / wind |
strings |
strings (rich harmonics) |
epiano |
electric piano |
bell |
bell |
marimba |
marimba |
bass |
bass |
music_box |
music box |
Or roll your own harmonic table:
Tone(freq=440, partials=[(1, 1.0), (2, 0.5), (3, 0.25), (5, 0.1)])
Tone(freq=440, detune=12) # slight detune, warmer
Tone(freq=440, tremolo=(8, 0.6)) # amplitude wobble
Volume curves
Audio("bgm.mp3", at=0, volume_curve=[(0, 0), (3, 1), (6, 0)])
Audio("x.mp3", volume_curve=[0.0, 0.5, 1.0]) # one per second
Audio("x.mp3", at=1.0, volume_curve=[(1,0),(3,1)]) # absolute seconds OK
Groups & other effects
from codeanim import AudioGroup, noise, pulse
sfx = AudioGroup([whoosh(at=2.0), beep(880, at=3.0), pulse(4, at=5.0)],
name="sfx")
sfx.volume = 0.6 # whole-group gain
sfx.shift(0.5) # shift everything later
sfx.mute() / sfx.unmute()
scene.add_audio(sfx)
scene.add_audio(noise(duration=3.0, volume=0.12, color="brown")) # wind
scene.add_audio(pulse(8, interval=0.08)) # typewriter
Everything is pure standard library — no numpy. Mixing is delegated to
ffmpeg (adelay + amix + aecho + pan).
codeanim script.py --list-audio # show the timeline (with note names)
codeanim script.py --no-audio # drop audio, video only
GIF has no audio. With audio tracks present, exporting a GIF is a loud error suggesting
.mp4/.webm, not a silent drop.
Composing a scene
Groups
from codeanim import Group, Rect, Circle
card = Group(cx=640, cy=360)
card.add(Rect(cx=0, cy=0, w=300, h=200, fill="#1e293b"))
card.add(Circle(cx=0, cy=-60, r=30, fill="#38bdf8"))
card.rotation.keys([(0, 0), (2, 360)])
card.opacity.keys([(0, 0), (0.6, 1)])
scene.add(card)
Inside a group, (0, 0) is the group centre. Parent rotation / scale /
opacity propagate to the whole subtree. Nesting works.
Timeline
from codeanim import seq, par
total = seq(scene, [
lambda s: add_title(scene, start=s),
lambda s: par(scene, [ # these two run together
lambda t: add_logo(scene, start=t),
lambda t: add_counter(scene, start=t),
]),
lambda s: add_outro(scene, start=s),
])
scene.duration = total
Or pin how long each clip should take:
seq(scene, [
add_title, # whatever the clip returns
(add_ball, 2.0), # at least 2 seconds
(add_logo, 1.5, 0.3), # at least 1.5s, then 0.3s of silence
{"clip": add_outro, "span": 2.0, "gap": 0.5},
])
seq(scene, [a, b, c], gap=0.5) # uniform gap between clips
The requested span is a lower bound — a longer clip is never truncated:
| clip returns | you asked | actual |
|---|---|---|
| 0.5s | 2.0 | 2.0s (padded) |
| 3.0s | 1.0 | 3.0s (clip wins) |
Reusable fragments
my_project/
├── main.py entry
├── title.py title fragment
├── ball.py ball fragment
└── logo.py intro fragment
# title.py
from codeanim import Text
def add_title(scene, start=0.0, title="Hello"):
t = Text(title, cx=scene.width/2, cy=scene.height/2,
font_size=96, fill="white", anchor="center")
t.opacity.keys([(start, 0), (start + 0.9, 1)])
scene.add(t, z=10)
return 1.5 # this clip takes 1.5s
Sibling .py files just import each other — the engine puts the script's
directory on sys.path.
Disk safety
The easiest way to blow up a device with high-quality animation: 4K / 60fps / 60s of PNG frames is about 21 GB. Three layers of protection:
1. Zero-disk by default. stream mode pipes rendered frames straight into
ffmpeg's stdin. No intermediate files at all — disk usage equals the final
video.
2. If you do ask for disk, do the math first. Only --frames /
--keep-frames use disk mode, and that path estimates space up front:
Not enough disk space for the intermediate PNG frames.
frame size: 3840 x 2160
frames: 3600
needed: 15.30 GB
available: 2.10 GB (/mnt/data, 15% headroom reserved)
Three ways out (the first is recommended):
1. Drop --frames / --keep-frames and use the default zero-disk streaming:
codeanim your_script.py -o out.mp4
2. Write to a roomier location:
codeanim your_script.py --frames /other/drive/dir/
3. Lower the resolution or frame rate.
3. A live red line during render. Streaming mode also checks free space
every 40 frames and aborts below --free-margin. Temp files are cleaned up on
success, error, and Ctrl-C.
Output formats
| Format | Use for | How | Alpha |
|---|---|---|---|
| MP4 (H.264) | default, best compatibility | -o out.mp4 |
— |
| WebM (VP9) | small files | -o out.webm |
yes* |
| MOV | Apple ecosystem | -o out.mov |
ProRes 4444 |
| MKV | generic container | -o out.mkv |
— |
| GIF | chat, docs | --gif |
— |
| PNG sequence | hand off to AE / Blender | --frames dir/ |
yes |
| Single PNG | check one moment | --snapshot 2.0 |
yes |
* WebM alpha depends on whether your libvpx was built with it. CodeAnim actually probes it (encodes a transparent sample and decodes it back), and tells you to use MOV instead of silently writing an opaque file.
Transparency
scene = Scene(1280, 720, background=None) # None = transparent
codeanim overlay.py -o overlay.mov # ProRes 4444
Drop it straight onto a Premiere / Final Cut timeline or a web <video>.
Design constraints
- No GUI. Never opens a window, never a player.
- Pure-function scene.
f(t)is independently evaluable at any moment — so seeking, reversing, and multiprocess rendering all just work. There are dedicated regression tests for this. - Scriptable. Fits in a Makefile, CI, GitHub Actions.
- Command line first. Every feature is reachable from a flag.
- Errors in plain language. Missing ffmpeg tells you how to install it; script errors show only your file and line; space / container problems give concrete fixes instead of a stack trace.
Testing
python tests/test_codeanim.py
527 assertions covering colour, easing, keyframes, purity, centre positioning, group transforms, gradients / shadows / perspective, particles, images, sprite animation, audio (import + generate + mixing + curves + voices + ADSR + pan/echo/reverb + groups), music theory, paths, Digits formatting, timelines, clip spans, layer order, sugar, hot reload, in-terminal preview, parameter validation, disk budgeting, encoder args, supersampling.
Examples
| File | Shows |
|---|---|
examples/promo/ |
a full 19s 1080p promo, built with the engine itself |
examples/demo.py |
title card: seq/par + Group + Digits + z layers |
examples/chart.py |
bar chart + line + rolling numbers |
examples/particles.py |
300+ primitives, performance |
examples/media.py |
images + sprite animation + audio |
examples/showcase.py |
gradients / shadows / perspective / particles / text fit |
examples/music_path.py |
music notation, voices, balls flying on beziers |
examples/alpha_overlay.py |
transparent background for compositing |
At a glance
Rendering
- Zero-disk streaming (disk usage = final video size)
- 2× supersampled anti-aliasing
- Multiprocess parallel (frames are independent)
- Static pre-composition + fast path
- Automatic CJK font discovery (incl.
.ttc)
Graphics
- Primitives:
CircleRectLineTextImagePathDigitsGroup - Gradients: linear / radial / conic, uneven stops
- Drop shadows with blur / spread / offset
- 3D-ish perspective (quad warp)
- Particles: burst, fountain, snow, sparkle, ripple — reproducible
- Paths: bezier, Catmull-Rom splines, arcs, polygons,
follow(),along() - 25 easing curves, colour interpolation
Audio
- Import any format ffmpeg reads
- Generate in code:
beepchimesweepwhoosharpeggiomelodychord_soundnoisepulse - Music theory:
notechordscaleparse_melody - 11 voices + custom harmonic tables
- ADSR envelopes, vibrato, tremolo, detune
- Volume curves, pan, echo, reverb, brightness
- Groups with batch gain / shift / mute
- Pure standard library — no numpy
Workflow
--watchhot reload with live preview--inlinein-terminal rendering (half-block characters)--previewrender one frame and open it--layersdraw-order inspectordoctordependency check- Disk budgeting and live guards
- Errors show only your file and line
--chfor Chinese output (English by default)
Metadata
Release files for codeanim-py 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| codeanim_py-0.4.0.tar.gz | 212.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| codeanim_py-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 383.7 kB
Release files / codeanim_py-0.4.0.tar.gz
| Download URL | codeanim_py-0.4.0.tar.gz |
|---|---|
| Size | 212.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0d54e6b0fe8ece184a1eef91cd21f08aefa951a8cbd0ea93cbb29cef7f94cdb8
|
|
BLAKE2b-256 checksum How to use checksums |
3d37934ecebb2febd8b4585d919f16b5279c63a8f5ebffb0b23506cda8cfbb97
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / codeanim_py-0.4.0-py3-none-any.whl
| Download URL | codeanim_py-0.4.0-py3-none-any.whl |
|---|---|
| Size | 171.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f71fa13b04b900c9402bf89678df6c3348f7f4756d2fe0c5945a28be976f85d1
|
|
BLAKE2b-256 checksum How to use checksums |
27aa5b9e9c89642bb45bdbd6aac1fdecb031521753804652b37f5bf64367fd2d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|