Overview
What is BEFLIX
BEFLIX — short for Bell Flicks — is a filmmaking language created by Ken Knowlton at Bell Telephone Laboratories in 1963. It was one of the first programming languages designed specifically for producing animated films by computer. BEFLIX programs ran on an IBM 7094 mainframe, at the time the most powerful computer at Bell Labs, and rendered their output to 35mm film via a Stromberg-Carlson SC-4020 microfilm recorder — a CRT that photographed each frame directly onto film stock.
The language gained its place in art history through a remarkable collaboration between Knowlton and the artist Stan VanDerBeek. Together they produced the Poem Field series (1966–69), a cycle of short films that rank among the earliest computer-animated art films ever made. VanDerBeek would describe compositions in terms of BEFLIX commands — dissolves, level translations, cellular growth patterns — and Knowlton would encode them. The films were projected inside VanDerBeek's Movie-Drome, a repurposed grain silo on the Stony Point commune in New York, as part of his vision for an immersive, universal visual language. This partnership was part of the pioneering wave of artist-engineer collaborations at Bell Labs that also included Lillian Schwartz, Michael Noll, and Edward Zajac. You can see examples of VanDerBeek's BEFLIX work at ragnardigital.art.
What is BEFLIX Studio
BEFLIX Studio is a faithful browser-based recreation of Knowlton's original command language. It implements the full BEFLIX instruction set — drawing primitives, level transformations, cellular automata, dissolves, and frame capture — running entirely in your browser with no installation required. The grid is the same 252×184 pixels at 8 gray levels as the 1963 original.
BEFLIX Studio adds three capabilities the original never had: color palettes that map the 8 gray levels to 8 RGB colors, render modes that simulate historical display technologies (CRT phosphor, SC-4020 microfilm, mosaic, halftone, and more), and an AI assistant that lets you describe films in natural language and have them written for you. Color and rendering are applied purely at render time — the underlying grid remains a grayscale document, exactly as Knowlton designed it.
The Mental Model
Everything in BEFLIX reduces to four concepts:
1. A grid — 252 columns by 184 rows of pixels.
2. Gray levels — each pixel holds one of 8 values:
0 (black) through 7 (brightest).
3. Commands — instructions that modify the grid by
drawing shapes, transforming levels, or querying pixel values.
4. Frames — snapshots of the grid captured for playback
as animation.
Drawing commands change the grid silently. Only frame commands
(FRAME, WAIT, DISOLV,
FADE) make the current state visible to the viewer. Think of it
as painting backstage, then pulling the curtain.
How Color Works
BEFLIX scripts never specify color. They only set gray levels 0–7. Color is applied at render time via palette lookup tables: each palette maps the 8 gray levels to 8 RGB colors. Switching palettes re-colors everything on the canvas instantly, without changing a single pixel value in the grid.
This mirrors VanDerBeek's historical process. After receiving grayscale film output from the SC-4020, he colorized it by hand using colored gels and optical printing techniques in his Movie-Drome. The Gel render effect in BEFLIX Studio simulates these physical gel overlays.
Command Spellings
Several BEFLIX commands have unusual spellings: DISOLV,
STRECH, COLUM, RETREV,
TRANSLAT. These are not typos — they are
Knowlton's original abbreviations from 1963.
BEFLIX was implemented in FORTRAN II and FAP on the IBM 7094, and its
commands were encoded on 80-column punch cards. The truncated spellings
reflect the terse naming conventions of that era. DISOLV
appears by name in Knowlton's 1964 paper “A Computer Technique for
Producing Animated Movies.” BEFLIX Studio preserves these spellings
for historical fidelity. Where convenient, modern aliases are also
accepted: DISSOLVE works as a shortcut for
DISOLV with the random pattern, and READ works
identically to RETREV.
The No-Undo Constraint
Every command permanently modifies the grid. There is no undo. This is not a
limitation — it is the defining constraint that shaped VanDerBeek's
aesthetic. Compositions build through accumulation and
transformation, not subtraction. The grid persists between frames
until you explicitly CLEAR it. Layers pile up. Dissolves eat
into existing imagery. Growth patterns spread across whatever is already
there. This constraint is what gives BEFLIX its distinctive layered,
palimpsest quality — every frame carries the ghost of everything that
came before it.
Getting Started
This tutorial walks you through writing your first BEFLIX animation, one command at a time. Each step shows the complete script so far and explains what happens visually.
Welcome Overlay
First-time visitors see a 3-step orientation overlay introducing the
Studio's layout and workflow. At the end, a Start Coding
button opens the 1963 tab. When dismissed, a default animation auto-plays
so the canvas is not blank. The overlay is shown once per browser;
dismissal is stored in localStorage
(beflix-welcomed).
Step 1: Open the Studio
Navigate to BEFLIX Studio. You will see the code editor on the right and the canvas on the left. The canvas starts blank (all pixels at level 0, black). The editor is where you type BEFLIX commands, one per line.
Step 2: Clear the Grid
CLEAR 0
Start with an explicitly black grid. CLEAR 0 sets every pixel
to level 0 (black). This is good practice at the top of any script —
it guarantees a known starting state.
Step 3: Draw Some Text
CLEAR 0 TEXT 80 80 "HELLO" 7 3
TEXT draws bitmap text at position (80, 80) using level 7
(the brightest white) at scale 3 (large characters). The text appears on the
grid but is not yet part of the animation — no frame has been captured.
Step 4: Capture a Frame
CLEAR 0 TEXT 80 80 "HELLO" 7 3 FRAME 24
FRAME 24 captures 24 copies of the current grid state. At
the default 12 fps, that is 2 seconds of “HELLO” displayed
on screen. Without a FRAME command, nothing is recorded.
Step 5: Add a Dissolve Transition
CLEAR 0 TEXT 80 80 "HELLO" 7 3 FRAME 24 DISOLV 0 12 SI
DISOLV 0 12 SI performs a spiral-inward dissolve, progressively
replacing pixels with level 0 (black) over 12 frames (1 second). The
dissolve starts from the edges and spirals toward the center — a
dramatic, theatrical transition that eats away at the “HELLO”
text.
Step 6: Draw More
CLEAR 0 TEXT 80 80 "HELLO" 7 3 FRAME 24 DISOLV 0 12 SI TEXT 60 80 "WORLD" 7 2
New text is drawn on whatever the dissolve left behind. Because the dissolve may not have fully completed to black (depending on how many pixels remained), “WORLD” is layered on top of the residue. This is the accumulation principle at work — every command builds on the current grid state.
Step 7: Hold the Result
CLEAR 0 TEXT 80 80 "HELLO" 7 3 FRAME 24 DISOLV 0 12 SI TEXT 60 80 "WORLD" 7 2 WAIT 24
WAIT 24 is functionally identical to FRAME 24
— it captures 24 frames of the current grid. The difference is
semantic: WAIT implies a deliberate pause, holding the current
composition for the viewer to absorb.
Step 8: Fade Out
CLEAR 0 TEXT 80 80 "HELLO" 7 3 FRAME 24 DISOLV 0 12 SI TEXT 60 80 "WORLD" 7 2 WAIT 24 FADE 0 12
FADE 0 12 smoothly interpolates every pixel toward level 0
(black) over 12 frames. Unlike DISOLV, which replaces pixels
one at a time, FADE shifts all pixel levels simultaneously
— a true crossfade to black.
Step 9: Render and Play
Click Render (the punch card icon in the 1963 tab, or press Ctrl+Enter) to render the script. Then press Space to play the animation. Try switching palettes in the Post FX tab — Poem Field Warm gives the output VanDerBeek's characteristic amber-and-orange look.
File Bar
The file bar above the canvas contains buttons for common file and editing
operations: New, Save,
Open, Share, Undo, and
Redo. The New Project button (page icon)
clears the editor, canvas, and all state for a fresh start. The keyboard
shortcut is Ctrl+N.
Ctrl+G to locate code ↔ frame. When your cursor is in
the editor, the canvas jumps to the frame that shows the result of that line.
When you're viewing the canvas, it jumps the editor to the line that produced
the current frame.
Slash-Command Snippets
Type / in the code editor to open a popup menu of ready-made
code snippets. A filterable list appears inline; continue typing to narrow
the results. Use Arrow Up / Arrow Down
to navigate the list and Enter to insert the selected
snippet at the cursor. Press Escape to close the menu
without inserting anything.
Snippets are organized into seven categories:
| Category | Contents |
|---|---|
| Shapes | Rectangles, circles, arcs, borders, lines |
| Text | Single text lines, multi-line text layouts |
| Transitions | Dissolves, fades, wipes |
| Effects | Noise fills, grow patterns, smooth, invert |
| Animation | Scroll loops, pulse loops, color cycling |
| Timing | Frame holds, waits, timed pauses |
| Scenes | Multi-part scene templates with transitions |
Each snippet inserts a complete block of BEFLIX code with sensible defaults. After insertion, edit the values to suit your composition. Snippets are a fast way to scaffold common patterns without typing every command from memory.
/fade
shows all snippets with "fade" in their name or category. Typing
/ alone shows the full list.
Core Concepts
The Grid
The BEFLIX grid is 252 columns × 184 rows of pixels — the exact resolution of Knowlton's original 1963 system. Coordinates use an origin of (0, 0) at the top-left corner. The X axis increases rightward to a maximum of 251. The Y axis increases downward to a maximum of 183. All drawing commands reference this coordinate system.
Gray Levels
Every pixel on the grid holds one of 8 gray levels, numbered 0 through 7. Level 0 is black; level 7 is the brightest white. There are no intermediate fractional values — the full visual vocabulary of BEFLIX consists of these 8 discrete shades.
Every drawing command includes a level parameter — you always specify which shade you are painting with. There is no separate “set color” command. The level is always part of the command itself.
Frames vs Drawing
Drawing commands (PAINT, LINE, TEXT,
CIRCLE, etc.) modify the grid silently —
nothing is visible to the viewer until a frame is captured. Only frame
commands (FRAME, WAIT, DISOLV,
FADE) capture the grid state as animation frames.
This means you can stack many drawing and transform operations between frame commands to build complex single-frame effects. Think of it like painting backstage, then pulling the curtain: the audience only sees the result when you choose to reveal it.
The Level Parameter
Every drawing command takes a level (0–7) as one of its arguments. The level specifies which gray shade the command paints with. There is no “set color first, then draw” workflow — the level is always embedded directly in the command.
CLEAR 0 ; whole grid → level 0 (black) PAINT 10 20 80 60 5 ; rectangle → level 5 TEXT 80 80 "HI" 7 2 ; text → level 7 (brightest) LINE 0 0 251 183 3 ; line → level 3
Accumulation
There is no undo. Each command permanently overwrites the pixels it touches. The grid persists between frames — it is never automatically cleared. Compositions build through layering: you draw on top of what is already there.
Use TRANSLAT to globally shift levels. Use GROW to
spread patterns outward from existing shapes. Use DISOLV to
transition between states. Use CLEAR when you need a fresh
start.
This constraint is the soul of VanDerBeek's aesthetic. Every frame in the Poem Field films carries traces of everything that came before it — a visual archaeology of accumulated transformations.
Drawing Commands
Drawing commands are the primitives that stamp shapes, text, and patterns
onto the grid. Each command takes a gray level parameter that specifies the
shade being painted. Drawing commands modify the grid silently — you
must use a frame command (FRAME, WAIT,
DISOLV, FADE) afterward to make the result
visible in the animation.
CLEAR
CLEAR [level]
level— gray level to fill the grid with (0–7, default 0 = black)
Fill the entire grid with a single gray level. If no level is specified, the default is 0 (black). This is the only way to guarantee a clean starting state — use it between scenes to reset the canvas.
CLEAR 0 ; fill entire grid with black CLEAR 4 ; fill entire grid with mid-gray CLEAR 7 ; fill entire grid with white
CLEAR is not part of the original 1963 BEFLIX language. In the
original, you would PAINT the full grid dimensions to achieve
the same effect. BEFLIX Studio adds it as a convenience.
PAINT
PAINT x y w h level
x— left edge position (0–251)y— top edge position (0–183)w— width in pixelsh— height in pixelslevel— gray level (0=black, 7=white)
Fill a rectangle at position (x, y) with dimensions w × h pixels, using the specified gray level. This is the fundamental rectangle primitive — the most basic drawing command in BEFLIX.
PAINT 10 20 80 60 5 ; 80×60 rectangle at (10,20), level 5 PAINT 0 0 252 184 0 ; fill entire grid with black (same as CLEAR 0) PAINT 100 80 50 20 7 ; bright horizontal bar
LINE
LINE x1 y1 x2 y2 level
x1, y1— start point coordinatesx2, y2— end point coordinateslevel— gray level (0–7)
Draw a straight line from (x1, y1) to (x2, y2) using Bresenham's line algorithm. The line is 1 pixel wide.
LINE 0 0 251 183 7 ; diagonal corner to corner, brightest LINE 126 0 126 183 3 ; vertical center line, mid-gray LINE 0 92 251 92 5 ; horizontal center line
CIRCLE
CIRCLE cx cy r level [FILL]
cx, cy— center point coordinatesr— radius in pixelslevel— gray level (0–7)FILL— optional keyword; fill the circle solid
Draw a circle centered at (cx, cy) with radius
r pixels. By default, only the outline is drawn. Add the
FILL keyword to draw a solid filled circle.
CIRCLE 126 92 40 7 ; outline circle, brightest CIRCLE 126 92 40 5 FILL ; filled circle, level 5 CIRCLE 60 60 20 3 ; small outline circle
CIRCLE is not part of the original 1963 BEFLIX language. The
original system had no circle primitive — circles had to be
approximated with careful use of PAINT and
GROW. BEFLIX Studio adds it as a convenience.
ARC
ARC cx cy r start end level [FILL]
cx, cy— center point coordinatesr— radius in pixelsstart— start angle in degrees (0 = 3 o'clock)end— end angle in degrees, measured clockwiselevel— gray level (0–7)FILL— optional keyword; draw a filled wedge
Draw an arc centered at (cx, cy) with radius
r, sweeping from start to end degrees. Angles
are measured clockwise from the positive X axis (3 o'clock position).
Add the FILL keyword to create a wedge (pie slice) instead
of an open arc.
ARC 126 92 50 0 180 7 ; top semicircle outline ARC 126 92 50 45 135 6 FILL ; filled wedge, level 6 ARC 126 92 80 270 360 4 ; quarter arc, bottom-right
TEXT
TEXT x y "string" level [scale]
x, y— top-left position of the text"string"— text to draw (A–Z, 0–9, punctuation; must be in double quotes)level— gray level (0–7)scale— optional size multiplier (1–5, default 1). Scale 1 = 5×7px per character
Draw bitmap text at position (x, y) using the specified gray level. Scale 2 doubles character size to 10×14, scale 3 to 15×21, and so on. In SC-4020 render mode, a condensed 4×7 character set is used instead, matching the font of the original hardware.
The available character set includes: A–Z, 0–9, and basic punctuation. Text strings must be enclosed in double quotes.
TEXT 80 80 "HELLO WORLD" 7 3 ; large bright text TEXT 10 170 "BEFLIX 1963" 4 1 ; small, mid-bright TEXT 20 20 "POEM FIELD" 7 5 ; very large, maximum brightness
BORDER
BORDER x y w h thickness level
x, y— top-left corner positionw, h— outer dimensions of the border rectanglethickness— border width in pixelslevel— gray level (0–7)
Draw a rectangular border (outline only). The interior of the rectangle is not affected.
BORDER 10 10 232 164 3 7 ; 3px bright border around most of the grid BORDER 0 0 252 184 1 5 ; 1px border at grid edges BORDER 50 40 100 80 5 2 ; thick dim border, centered region
COPY
COPY sx sy w h dx dy
sx, sy— source position (top-left corner)w, h— size of the region to copydx, dy— destination position (top-left corner)
Copy a rectangular region to a new position on the grid. The copy overwrites whatever is at the destination. The source region is not cleared — it remains unchanged.
COPY 0 0 126 92 126 92 ; copy top-left quadrant to bottom-right COPY 50 40 80 60 10 10 ; copy a region to near the origin
INVERT
INVERT [x y w h]
x, y, w, h— optional region; if omitted, the entire grid is inverted
Flip all gray levels to their complement: 0 becomes 7, 1 becomes 6, 2 becomes 5, 3 becomes 4, and vice versa. With no arguments, the entire grid is inverted. Provide optional x y w h to restrict the inversion to a rectangular region.
INVERT ; invert the entire grid INVERT 50 40 100 80 ; invert only a region
SCROLL
SCROLL dx dy SCROLL direction amount
Shift the entire grid. Two forms are supported:
Numeric form: dx shifts horizontally (positive = right, negative = left), dy shifts vertically (positive = down, negative = up).
Direction form: direction is one of
U (up), D (down), L (left),
R (right), followed by amount in pixels.
Pixels that scroll off the edge are lost. Vacated pixels become level 0 (black).
SCROLL 10 0 ; shift right 10 pixels (numeric) SCROLL 0 -5 ; shift up 5 pixels (numeric) SCROLL R 10 ; shift right 10 pixels (direction) SCROLL U 5 ; shift up 5 pixels (direction) SCROLL -3 2 ; shift left 3, down 2 (numeric only)
SCROLL with REPEAT for scrolling text
effects: draw text off-screen, then scroll it into view one pixel at a time,
capturing a frame at each step. The direction form is easier to read;
the numeric form allows diagonal scrolling.
NOISE
NOISE x y w h [min max]
x, y— top-left corner positionw, h— region dimensionsmin, max— optional gray level range (default 0–7). Each pixel gets a random level within this range.
Fill a rectangular region with random gray levels. Each pixel in the region is independently set to a random value. The default range is 0–7 (all levels). Specify min and max to restrict the range to a narrower band of levels.
NOISE 0 0 252 184 0 7 ; full grid, all levels NOISE 50 50 100 80 2 6 ; region, levels 2–6 only NOISE 0 0 252 184 0 1 ; sparse random seeds (mostly black)
Transform Commands
Transform commands manipulate the pixels already on the grid. Unlike drawing
commands that stamp new shapes, transforms read and rewrite what is already
there. They are the most powerful tools in BEFLIX — the source of its
distinctive visual language. VanDerBeek's Poem Field films derive
their mesmerizing, pulsating quality almost entirely from the interplay of
TRANSLAT, GROW, and DISOLV.
TRANSLAT
TRANSLAT t0 t1 t2 t3 t4 t5 t6 t7 [x y w h]
t0–t7— eight target levels: pixels at level 0 become t0, level 1 becomes t1, … level 7 becomes t7x, y, w, h— optional region; if omitted, the entire grid is translated
The most important command in BEFLIX. TRANSLAT
defines a level translation table: every pixel's gray level is remapped
according to the eight arguments. The remapping is applied simultaneously to all pixels.
Identity (no change):
TRANSLAT 0 1 2 3 4 5 6 7 ; every level maps to itself
Posterize (binary threshold):
TRANSLAT 0 0 0 0 7 7 7 7 ; levels 0–3 → black, 4–7 → white
Color cycle (rotate all levels up by 1):
TRANSLAT 1 2 3 4 5 6 7 0 ; each level shifts up; 7 wraps to 0
Fade toward black:
TRANSLAT 0 0 1 2 3 4 5 6 ; every level drops by one (0 and 1 both → 0)
Strobe (alternating black and white):
TRANSLAT 0 7 0 7 0 7 0 7 ; even levels → black, odd levels → white
Brighten:
TRANSLAT 1 2 3 4 5 6 7 7 ; every level goes up by one (7 stays 7)
Regional application:
TRANSLAT 7 6 5 4 3 2 1 0 50 40 100 80 ; invert levels in a region only
TRANSLAT is the key to BEFLIX animation. Apply it inside a
REPEAT loop to create cycling, pulsing, and fading effects.
VanDerBeek used color cycling extensively in the Poem Field films
— the shimmering, breathing quality of those works comes directly from
TRANSLAT applied frame after frame.
GROW
GROW ns1 ns2 ns3 [x y w h]
ns1— source level: pixels at this level are candidates to changens2— neighbor level: the candidate must have at least one cardinal neighbor (up/down/left/right) at this levelns3— result level: matching candidates become this levelx, y, w, h— optional region; if omitted, the entire grid is processed
Cellular automaton — the second most distinctive BEFLIX
command. GROW applies a single-step spreading rule.
The rule is applied simultaneously to all pixels.
Because only the 4 cardinal neighbors are checked (not 8), a single
point seed grows into a diamond shape, not a circle.
Basic growth — black pixels next to bright become gray:
CLEAR 0 PAINT 126 92 1 1 7 ; single bright pixel in the center GROW 0 7 5 ; black pixels next to bright → level 5 FRAME 1
Chaining for concentric rings:
CLEAR 0 PAINT 126 92 1 1 7 ; single bright seed REPEAT 10 GROW 0 7 5 ; ring of 5 forms around 7 GROW 0 5 3 ; ring of 3 forms around 5 FRAME 2 END
Using noise seeds for organic shapes:
NOISE 0 0 252 184 0 1 ; sparse random seeds at level 1 TRANSLAT 0 7 0 0 0 0 0 0 ; promote level 1 → 7 (bright seeds) REPEAT 20 GROW 0 7 4 ; black near bright → level 4 FRAME 2 END
GROW is a cellular automaton. Each application spreads the
pattern one pixel outward in the four cardinal directions. Chain multiple
GROW calls with different level arguments between frames to
build complex organic patterns with concentric bands of gray.
SMOOTH
SMOOTH [x y w h]
x, y, w, h— optional region; if omitted, the entire grid is smoothed
Apply a 2×2 majority vote to each pixel: each pixel takes the most common gray level value in its 2×2 neighborhood. This rounds jagged edges into organic curves. Repeated application creates progressively smoother, blob-like shapes.
NOISE 0 0 252 184 0 7 REPEAT 5 SMOOTH FRAME 3 END
Apply SMOOTH to a specific region to selectively soften one
area while leaving the rest of the grid untouched:
NOISE 0 0 252 184 0 7 SMOOTH 50 40 150 100 ; smooth only the center region FRAME 12
SMOOTH after NOISE or GROW to
soften edges. Multiple passes create organic, blob-like forms that recall
biological structures. Combine with GROW in alternation for
the “bloom” effect used in the Poem Field films.
BLOW
BLOW x y w h factor
x, y— top-left corner of the regionw, h— region dimensionsfactor— magnification level (minimum 2). The top-left 1/factor of the region is enlarged to fill it.
Magnify the top-left portion of the specified region to fill the whole region.
Unlike ZOOMIN (which uses flat pixel replication),
BLOW creates mosaic-textured sub-pixels —
each enlarged pixel is rendered as a patterned block rather than a solid
square. This mosaic texture gives enlargements a distinctive, grainy quality.
TEXT 10 10 "BEFLIX" 7 1 BLOW 0 0 252 184 4 ; magnify with mosaic texture FRAME 24
BLOW creates the distinctive mosaic-textured enlargements seen
in VanDerBeek's films. Use it on text or NOISE patterns for
rich, granular textures. Compare with ZOOMIN for the
difference between textured and clean enlargement.
ZOOMIN
ZOOMIN x y w h factor
x, y— top-left corner of the regionw, h— region dimensionsfactor— magnification level (minimum 2). The center portion is enlarged using clean pixel replication.
Magnify the center of the specified region by factor using clean pixel replication. Each pixel is scaled to a solid block of factor×factor pixels. The result is a sharp, clean enlargement with no added texture.
ZOOMIN 50 30 150 120 3 ; 3x zoom into center of region ZOOMIN 0 0 252 184 2 ; 2x zoom into center of full grid
REDUCE
REDUCE x y w h factor
x, y— top-left corner of the regionw, h— region dimensionsfactor— reduction factor (minimum 2). Averages blocks of factor×factor pixels into single pixels.
Shrink the specified region by averaging blocks of factor×factor pixels into single pixels. The miniature version is centered within the original region, surrounded by the unchanged original content.
REDUCE 0 0 252 184 2 ; half-size miniature, centered REDUCE 50 30 150 120 3 ; third-size reduction of a region
STRECH
STRECH x y w h H|V factor
x, y— top-left corner of the regionw, h— region dimensionsH|V— axis:Hfor horizontal stretch,Vfor vertical stretchfactor— stretch factor (minimum 2). Center pixels are replicated to fill the expanded area.
Stretch the center portion of a region along one axis. H
stretches horizontally; V stretches vertically. The center
pixels are replicated to fill the expanded area. Uses Knowlton's original
spelling (single T — STRECH, not
STRETCH).
STRECH 50 30 150 120 H 2 ; horizontal stretch, 2x STRECH 50 30 150 120 V 3 ; vertical stretch, 3x
PRESS
PRESS x y w h H|V factor
x, y— top-left corner of the regionw, h— region dimensionsH|V— axis:Hfor horizontal compress,Vfor vertical compressfactor— compression factor (minimum 2). Pixels are averaged along the chosen axis.
Compress a region by averaging pixels along one axis. The compressed result
is centered within the original region. PRESS is the inverse of
STRECH: where STRECH stretches, PRESS
squeezes.
PRESS 50 30 150 120 H 2 ; horizontal compress, 2x PRESS 50 30 150 120 V 2 ; vertical compress, 2x
COLUM
COLUM x w U|D amount
x— starting column positionw— width of the column range to shiftU|D— direction:Ushifts up,Dshifts downamount— number of pixels to shift (wraps around)
Cyclically shift columns from x to x+w
vertically. U shifts up; D shifts down. Content
wraps around — pixels that scroll off one edge reappear at the other.
Nothing is lost. This is Knowlton's original column operation.
COLUM 0 252 D 10 ; shift all columns down 10px (wraps) COLUM 0 252 U 5 ; shift all columns up 5px (wraps)
Apply COLUM to different column ranges to create wave
distortion effects:
REPEAT 20 COLUM 0 126 U 2 ; left half shifts up COLUM 126 126 D 2 ; right half shifts down FRAME 2 END
ROTATE
ROTATE x y w h U|D|L|R amount
x, y— top-left corner of the regionw, h— region dimensionsU|D|L|R— direction:Uup,Ddown,Lleft,Rrightamount— number of pixels to shift (wraps around the region boundaries)
Cyclically shift pixels within a rectangular region. Content wraps around
the region boundaries — pixels that move past one edge reappear at the
opposite edge. Directions: U (up), D (down),
L (left), R (right).
ROTATE 50 40 100 80 R 5 ; shift region right 5px (wraps) ROTATE 0 0 252 184 U 10 ; full grid cyclic shift up 10px ROTATE 80 60 90 70 L 3 ; shift region left 3px (wraps)
Animation Commands
Animation commands are what make BEFLIX a filmmaking language rather than a drawing tool. While drawing and transform commands modify the grid silently, animation commands capture the grid's current state as one or more frames in the output sequence. Without these commands, nothing is visible to the viewer.
FRAME
FRAME [count]
count— number of frames to capture (default 1). At 12fps: 12 = 1 second, 24 = 2 seconds.
Capture the current grid state as one or more animation frames. The optional
count parameter specifies how many copies of the current state to
record. The default count is 1. At the default playback rate of 12 fps,
FRAME 12 produces 1 second of footage.
Drawing commands between FRAME calls modify the grid silently
— only FRAME makes them visible in the final animation.
This is the fundamental capture mechanism: draw, then frame.
CLEAR 0 PAINT 50 50 100 80 7 FRAME 12 ; 1 second of white rectangle PAINT 60 60 80 60 3 FRAME 12 ; 1 second with gray rectangle overlaid
WAIT
WAIT count
count— number of frames to hold (at 12fps: 12 = 1 second, 24 = 2 seconds)
Identical to FRAME — captures count frames of
the current grid state. The difference is purely semantic:
WAIT implies a deliberate pause in the animation, while
FRAME implies a keyframe capture. Use whichever reads more
clearly in context.
WAIT 24 ; hold current state for 2 seconds WAIT 6 ; brief half-second pause
DISOLV
DISOLV level frames [pattern] [x y w h]
level— target gray level (0–7). All pixels will approach this level.frames— number of frames for the transition (at 12fps: 12 = 1 second)pattern— pixel replacement order: F, SI, SO, R, or L (default F). See table below.x, y, w, h— optional region; if omitted, the entire grid dissolves
Knowlton's dissolve — progressively replaces pixels with the target level over the specified number of frames. Each frame, a portion of the pixels are overwritten, creating a gradual transition. Uses Knowlton's original single-S spelling.
The optional pattern parameter controls the order in which pixels are replaced. Five patterns are available:
| Pattern | Name | Description |
|---|---|---|
F |
Random | Fisher-Yates shuffle — each pixel replaced in random order. The classic “TV static” dissolve. This is the default. |
SI |
Spiral Inward | Starts from the edges and spirals toward the center. Dramatic, theatrical. |
SO |
Spiral Outward | Starts from the center and spirals to the edges. Reveals or erases from a central point. |
R |
Wipe Right | Left-to-right, column-by-column replacement. Clean, cinematic. |
L |
Wipe Left | Right-to-left replacement. Reverse wipe. |
Provide optional x y w h to restrict the dissolve to a rectangular region of the grid.
DISOLV 0 12 SI ; spiral inward to black over 12 frames DISOLV 7 24 F ; random dissolve to white over 2 seconds DISOLV 0 18 R ; wipe right to black DISOLV 3 12 SO 50 40 100 80 ; spiral out to level 3 in a region
DISSOLVE
DISSOLVE level frames [x y w h]
level— target gray level (0–7)frames— number of frames for the transitionx, y, w, h— optional region
Convenience alias for DISOLV level frames F — performs a
random-pattern dissolve only. Use this when you want the default Fisher-Yates
random dissolve without specifying the pattern explicitly. For directional
dissolves (wipes, spirals), use DISOLV instead.
DISSOLVE 0 12 ; random dissolve to black over 12 frames DISSOLVE 7 24 50 40 100 80 ; random dissolve to white in a region
FADE
FADE level frames
level— target gray level (0=fade to black, 7=fade to white)frames— number of frames for the transition
Smoothly interpolate all pixels toward the target
level over the specified number of frames. Unlike
DISOLV (which replaces pixels one by one in some spatial
order), FADE shifts every pixel's gray level simultaneously,
one step at a time. The result is a true crossfade — every pixel
gradually converges on the target.
FADE 0 12 ; fade everything toward black over 1 second FADE 7 24 ; fade everything toward white over 2 seconds FADE 4 18 ; fade toward mid-gray over 1.5 seconds
Timing
The default playback rate is 12 frames per second —
Knowlton's original frame rate for the SC-4020 microfilm output.
FRAME 1 captures 1/12th of a second.
FRAME 12 captures exactly 1 second. All animation commands
(FRAME, WAIT, DISOLV,
FADE) use this same time base. The FPS can be adjusted in the
Post FX tab from 1 to 30. The frame counter in the playback bar shows both
frame numbers and duration in seconds (e.g.
Frame 20 / 32 (1.7s / 2.7s)).
| Frames | Duration at 12fps |
|---|---|
1 |
0.08s |
6 |
0.5s |
12 |
1s |
24 |
2s |
36 |
3s |
60 |
5s |
Flow Control
REPEAT count ... END
Repeat a block of commands count times. The entire block between REPEAT and its matching END executes repeatedly. Loops can be nested — inner loops run fully for each iteration of the outer loop.
REPEAT 10
SCROLL 5 0
FRAME 2
END
This shifts the grid right by 5 pixels and captures 2 frames, 10 times — creating a scrolling animation of 20 total frames.
Nested example:
REPEAT 5
REPEAT 3
GROW 0 7 4
FRAME 1
END
TRANSLAT 0 0 1 2 3 4 5 6
FRAME 6
END
Conditional Blocks
Three conditional block types test scanner values against the grid. Each takes one or more conditions in parentheses and executes the enclosed block based on the result.
IFANY (scanner op value) ... END — Execute the block if any of the listed conditions is true. Multiple conditions can be listed, and only one needs to match.
IFALL (scanner op value) ... END — Execute the block only if all of the listed conditions are true. Every condition must match.
IFNONE (scanner op value) ... END — Execute the block only if none of the listed conditions are true. The block runs when every condition fails.
Comparison Operators
| Operator | Meaning | Symbol |
|---|---|---|
E |
Equal | = |
NE |
Not Equal | ≠ |
G |
Greater Than | > |
L |
Less Than | < |
GE |
Greater or Equal | ≥ |
LE |
Less or Equal | ≤ |
The scanner must have been READ before testing its value:
SET A 100 100
READ A ; read grid value at (100,100) into A
IFANY (A E 0) ; if A's value equals 0...
WRITE A 7 ; ...write level 7 at A's position
END
Combining Loops and Conditionals
Loops and conditionals can be freely combined for complex behavior. This example walks a scanner across the grid, inverting each pixel based on its current brightness:
SET A 10 10
REPEAT 50
READ A
IFANY (A L 4) ; if current pixel is dark (level < 4)
WRITE A 7 ; make it bright
END
IFANY (A GE 4) ; if pixel is bright
WRITE A 0 ; make it dark
END
MOVE A R 5
FRAME 1
END
Scanners
Knowlton's 26 programmable scanners (A through Z) are virtual pointers that traverse the grid. They can read pixel values, write new values, and move in 8 directions. Scanners are BEFLIX's way of interacting with individual pixels and implementing logic based on grid state.
Scanner Basics
There are 26 scanners named A through Z. Each scanner has a position (x, y) on the grid and a value register that is set by READ. Think of them as cursors that can both paint and sense — they move across the grid, read what is there, and write new values based on conditions.
SET scanner x y
scanner— scanner name (A–Z)x— horizontal position (0–251)y— vertical position (0–183)
Position a scanner at coordinates (x, y). This must be called before using any other scanner command — an uninitialized scanner starts at (0, 0) with an undefined value register. Coordinates are clamped to the grid: x stays within 0–251, y within 0–183.
SET A 50 50 ; place scanner A at position (50, 50)
SET B 0 0 ; scanner B at top-left corner
SET C 251 183 ; bottom-right corner
SET a scanner before using it. While uninitialized scanners default to (0, 0), relying on this makes code harder to read. Be explicit.
MOVE scanner dir n
scanner— scanner name (A–Z)dir— direction: U, D, L, R, UR, UL, DR, DL (see table below)n— number of pixels to move (default 1)
Move a scanner by n pixels in a direction. There are 8 directions available:
| Direction | Meaning |
|---|---|
U | Up |
D | Down |
L | Left |
R | Right |
UR | Up-Right (diagonal) |
UL | Up-Left (diagonal) |
DR | Down-Right (diagonal) |
DL | Down-Left (diagonal) |
MOVE A R 10 ; move right 10 pixels
MOVE A U 5 ; move up 5 pixels
MOVE A DR 3 ; move diagonally down-right 3 pixels
Boundary behavior: if a move would push the scanner past
the grid edge, the position is clamped to the nearest valid coordinate.
The scanner stops at the boundary rather than wrapping around. Use
CONFINE to restrict movement to a smaller region.
WRITE scanner level
scanner— scanner name (A–Z)level— gray level to write (0–7)
Write a gray level (0–7) at the scanner's current position on the grid. Only the single pixel at the scanner's position is affected — the scanner does not move after writing. Combine WRITE with MOVE in a loop to draw pixel-by-pixel patterns.
WRITE A 7 ; set the pixel at A's position to level 7
; Draw a dotted horizontal line
SET A 10 92
REPEAT 30
WRITE A 7
MOVE A R 4 ; skip 3 pixels between dots
END
READ / RETREV scanner
scanner— scanner name (A–Z). The grid value at the scanner's position is stored in its value register.
Read the grid value at the scanner's current position into its value register. After reading, use IFANY, IFALL, or IFNONE to test the value and branch accordingly. The value register retains its last READ result until the next READ — if you move the scanner and test without reading again, you are testing the old position's value.
RETREV is Knowlton's original abbreviation of "retrieve" — it works identically to READ and is supported for historical compatibility.
READ before testing. Conditionals (IFANY, IFALL, IFNONE) test whatever value is stored in the scanner's register. If you haven't called READ since the last MOVE, the conditional tests the value from the scanner's previous position, not its current one.
SET A 100 50
READ A ; A.value = grid level at (100, 50)
IFANY (A E 7)
WRITE A 0 ; if it was bright, make it dark
END
CONFINE / FREE
CONFINE scanner area — Restrict a scanner's movement to a named area (defined with AREA). After CONFINE, every MOVE clamps the scanner's position to the area bounds — if a move would take it outside, the scanner stops at the boundary edge instead. The scanner can still WRITE and READ normally within the confined region.
FREE scanner — Remove the movement restriction, allowing the scanner to move anywhere on the full 252×184 grid again. A scanner that was clamped at an area boundary stays at that position after FREE.
AREA BOX 30 40 192 120
SET A 30 40
CONFINE A BOX
REPEAT 200
WRITE A 7
MOVE A R 1 ; stays within BOX bounds
FRAME 1
END
FREE A
SCAN
SCAN area WRITE level — Fill the entire named area with a single gray level. This is similar to PAINT but uses a named area instead of raw coordinates.
SCAN area READ scanner — Calculate the average brightness of all pixels in the named area and store the result in the scanner's value register. This is useful for analyzing the overall tone of a region.
AREA LEFT 0 0 126 184
AREA RIGHT 126 0 126 184
SCAN LEFT READ A ; A.value = avg brightness of left half
SCAN RIGHT READ B ; B.value = avg brightness of right half
IFANY (A G 4)
SCAN LEFT WRITE 0 ; if left half is bright, clear it
END
Scanner Example: Drawing a Diagonal Line
A simple animated line drawn from the top-left corner, one dot at a time:
SET A 0 0
REPEAT 92
WRITE A 7
MOVE A DR 2
FRAME 1
END
This draws a diagonal line from the top-left, placing a bright pixel and stepping diagonally down-right by 2 each frame.
Scanner Example: Conditional Painting
This example creates a sparse noise pattern, then walks a scanner across it, writing only on dark pixels:
; Create sparse noise pattern
CLEAR 0
NOISE 0 0 252 184 0 1
TRANSLAT 0 7 0 0 0 0 0 0 ; level 1 → level 7 (sparse bright dots)
FRAME 12
; Scanner walks and reads, writing only where grid is dark
SET A 10 10
REPEAT 50
READ A
IFANY (A E 0) ; only write on black pixels
WRITE A 5
END
MOVE A DR 2
FRAME 1
END
Areas & Subroutines
AREA name x y w h
name— area name (2+ characters, letters/numbers/underscore, cannot be a command name or single letter A–Z)x, y— top-left corner positionw, h— area dimensions
Define a named rectangular area on the grid. Once defined, the area name can be used anywhere that coordinates (x y w h) are expected. This makes scripts more readable and easier to modify — change the area definition in one place and every command that references it updates automatically.
AREA MYBOX 10 20 80 60
PAINT MYBOX 5 ; → PAINT 10 20 80 60 5
NOISE MYBOX 0 7 ; → NOISE 10 20 80 60 0 7
INVERT MYBOX ; → INVERT 10 20 80 60
GROW 0 7 5 MYBOX ; → GROW 0 7 5 10 20 80 60
Naming Rules
Area and subroutine names follow these rules:
| Rule | Detail |
|---|---|
| Minimum length | Names must be 2 or more characters |
| Allowed characters | Letters, numbers, and underscore only |
| Reserved words | Cannot be a command name (CLEAR, PAINT, GROW, etc.) |
| Single letters | Cannot be a single letter A–Z (those are scanner names) |
| Quoted strings | Area names inside quoted strings are NOT expanded: TEXT 10 80 "MYBOX" 7 2 prints the word "MYBOX" |
DEF name ... END
Define a reusable subroutine. Subroutines can contain any commands: drawing, animation, REPEAT, IF blocks, and even other DEF/CALL statements. Maximum nesting depth is 100 levels.
CALL name
Execute a previously defined subroutine. The same naming rules apply as for AREA.
Example — reusable sparkle effect:
DEF SPARKLE
NOISE 0 0 252 184 0 7
SMOOTH
FRAME 3
END
CLEAR 0
TEXT 80 80 "BEFLIX" 7 3
FRAME 24
CALL SPARKLE ; run the sparkle
TEXT 80 80 "BEFLIX" 7 3 ; redraw text
FRAME 24
CALL SPARKLE ; sparkle again
Example — reusable border pattern:
DEF BORDER_FLASH
BORDER 5 5 242 174 5 7
FRAME 3
BORDER 5 5 242 174 5 0
FRAME 3
END
CLEAR 0
TEXT 80 80 "HELLO" 7 3
REPEAT 5
CALL BORDER_FLASH
END
2026 Tab
The 2026 tab is a chat interface where you describe what you want a BEFLIX film to be — or how to change one — in plain English, and an LLM writes the script for you. The AI understands the full BEFLIX command set, knows compositional techniques from the Poemfield films, and produces complete, runnable scripts that are automatically applied to the editor. Switch to the 2026 tab by clicking its tab button.
Settings & Providers
Before using the 2026 tab you need an API key from one of the three supported providers. Click Settings + at the top of the 2026 tab to expand the settings panel. If no API key is configured, the settings panel opens automatically when you switch to the 2026 tab.
| Provider | Default Model | Get a Key |
|---|---|---|
| Anthropic | Claude Sonnet 4.5 | console.anthropic.com → API Keys |
| OpenAI | GPT-4o | platform.openai.com → API Keys |
| OpenRouter | Claude Sonnet 4.5 | openrouter.ai → Keys |
Select your provider from the dropdown, paste your API key, and click Save Settings. Your key is stored in the browser's local storage and persists across sessions. Each provider stores its key separately, so you can switch between providers without re-entering keys.
The Model field is optional. Leave it blank to use the
provider's default model. If you want to use a specific model (for example
claude-opus-4-0-20250514 or gpt-4-turbo), type its
model ID here.
AI Key
As an alternative to providing your own API key, you can enter a custom AI key in the settings panel. AI keys are issued to specific users and route AI requests through a server-side proxy instead of calling the provider API directly from the browser.
AI keys have daily rate limits managed on the server. When the daily limit is reached, requests are rejected until the next day. To use an AI key, select the AI Key option in the settings panel and paste your key. No provider selection or model configuration is needed — the proxy handles routing.
Chat Interface
The chat area shows a scrollable conversation between you and the AI. Type your message in the text area at the bottom and press Enter to send. Use Shift+Enter for a newline within your message.
The AI streams its response in real time. While streaming, the Send button becomes a Stop button — click it or press Escape to cancel generation.
The status bar below the chat shows the current model name, cumulative token usage (input and output), and a Clear button that resets the conversation.
Conversation context: The AI remembers earlier messages in the session. If you say "draw a circle" and then "now make it pulse," the AI understands "it" refers to the circle. Conversations reset when you refresh the page or click Clear.
Editor awareness: If the editor already has code when you send a message, the AI sees it. You can load an example, switch to the 2026 tab, and say "add a dissolve at the end" — the AI will modify the existing script rather than starting from scratch.
Auto-Apply
When the AI's response contains a BEFLIX code block, BEFLIX Studio automatically replaces the editor with the AI's code, renders the script, and starts playback if the script produced frames. Use Ctrl+Z to undo if you want to go back to your previous script.
Prompting Tips
Be visual and descriptive. The AI responds well to descriptions of what you want to see: "a field of random dots that slowly dissolve into horizontal stripes" works better than "use GROW and TRANSLAT commands."
Reference the Poemfield aesthetic. The AI knows the compositional vocabulary of VanDerBeek's films. Terms like "pulsing mosaic," "text dissolving into noise," or "layered growth patterns" produce authentic results.
Iterate. Start with a simple prompt, then refine: "make the text bigger," "slow down the dissolve," "add a second phase where everything inverts." The conversation context lets you build up complexity gradually.
Ask for modifications. Load any script — from the Examples tab, from a file, or your own work — and ask the AI to modify it. "Add a fade out at the end," "make the REPEAT loop run twice as long," or "replace the text with my name."
Learn from the output. Every AI response is real BEFLIX code. Read it in the 1963 tab to learn how commands work together. The AI adds comments explaining each section.
Rendering
Render Modes
BEFLIX Studio offers five render modes that change how the 252×184 grid is displayed. Each mode simulates a different output device or aesthetic from the era of early computer graphics.
Pixels — Sharp, clean pixel display. The clearest view of your grid data with each pixel rendered as a solid square. Best for editing and precise work where you need to see exact values.
Mosaic — Each pixel is rendered as a 3×3 pattern of sub-pixels with density proportional to the gray level. This creates the distinctive textured look of early computer graphics. This is how VanDerBeek's films actually looked on the SC-4020 output — not smooth gradients but clustered dots forming the illusion of tone.
Halftone — 5×5 dot cells that grow from center outward, simulating traditional halftone printing. Gives animations a printed, graphic quality reminiscent of newspaper reproductions of early computer art.
SC-4020 — Simulates the Stromberg-Carlson SC-4020 microfilm recorder, the actual output device of the original BEFLIX system. Features include: soft Gaussian beam dots (the SC-4020 used an electron beam to expose film), slight pixel bleed between adjacent dots, brightness falloff at frame edges (vignetting from the CRT), and the SC-4020's condensed 4×7 character generator for text. Switching to or from SC-4020 mode automatically re-renders the script because the text character width changes.
CRT — Soft, slightly blurred pixels simulating a CRT monitor display. Combine with the Scanlines and Bloom effects for an authentic retro look that evokes late-1960s computer terminals.
Palettes
Each palette maps the 8 gray levels (0–7) to 8 specific RGB colors. Switching palettes re-colors the entire animation instantly without changing the underlying grid data.
Built-in Palettes
| Palette | Description |
|---|---|
| Monochrome | Black to white — raw computer output, the default neutral palette |
| Phosphor Green | Black to green — classic CRT terminal colors |
| Phosphor Amber | Black to amber — warm CRT terminal aesthetic |
| Poem Field Warm | Black through deep reds to warm yellow — inspired by Poemfield No. 2 |
| Poem Field Cool | Black through blues to cool cyan — inspired by Poemfield No. 5 |
| Psychedelic | Rainbow mapping across all 8 levels |
| VanDerBeek | Purple through warm tones to yellow — VanDerBeek's signature palette |
Custom Palettes
You can create your own 8-color palettes. Click the + button next to the palette dropdown to open the palette editor.
The editor shows 8 numbered color swatches (levels 0–7). Click any swatch to open your operating system's native color picker. Changes preview live on the canvas as you pick colors. Give your palette a name and click Save.
Custom palettes appear in the dropdown under a “Custom” group, separate from the built-in palettes. They are saved to your browser's local storage and persist across sessions.
To edit an existing custom palette, select it from the dropdown and click +. The editor opens pre-filled with that palette's name and colors. To delete a custom palette, open it in the editor and click Delete. Built-in palette names are protected and cannot be overwritten.
Effects
Effects are post-processing filters applied on top of the rendered grid. Multiple effects can be active simultaneously and combine for richer visual results.
Scanlines — Horizontal CRT raster scan lines. Adds every-other-line darkening for an authentic monitor look. Pairs especially well with the CRT render mode.
Bloom — Phosphor bleed glow. Bright pixels bleed light into surrounding areas, simulating the phosphor persistence of CRT displays. Creates a soft halo around bright elements.
Grain — Random film grain overlay. Each frame gets a slightly different grain pattern, simulating 35mm film stock. Adds organic texture to the otherwise clean digital output.
Gel — Color gel overlay simulating VanDerBeek's optical printing process. Adds a diagonal warm-to-cool color wash, with brighter areas picking up more tint. This is the digital equivalent of VanDerBeek's physical colored gel sheets, which he used to add color to the monochrome SC-4020 output during optical printing.
SC-4020 Font
The SC-4020 render mode uses a condensed 4×7 character set, matching the original hardware's character generator. The normal render modes use a 5×7 character set. Because text character widths differ between modes, switching to or from SC-4020 mode automatically re-renders the script to recalculate text layout and positions.
Recording and Export
BEFLIX Studio provides several ways to save and share your work:
Export — Click the Export ▾ button to choose an export format:
WebM Video — Captures the animation as a WebM video at the current FPS setting. The active palette, render mode, and all effects are baked into the recorded video. A system Save As dialog lets you choose where to save the file.
GIF Animation — Encodes the animation as an animated GIF. The export runs in two phases: first, frames are composited (0–50%), then the GIF is encoded (50–100%). Progress is shown on the Export button. A system Save As dialog lets you choose where to save the file. GIF encoding runs entirely in the browser — no server or internet connection is required.
Save (💾) — Opens your system's file picker to save the current script as a .beflix text file. The file name appears above the editor, with a dot indicator when you have unsaved changes.
Load (📂) — Opens a file picker to load a previously saved .beflix file into the editor. The loaded file name is displayed above the editor.
Share (🔗) — Compresses the current script and encodes it into a shareable URL. The link is automatically copied to your clipboard. Anyone who opens the link will see the full BEFLIX Studio with your script loaded and ready to render. This works without any server — the entire script is embedded in the URL itself.
Auto-save — Your work is automatically saved to the browser's local storage as you type. If you close and reopen the studio, your last draft is restored automatically.
The FPS setting (1–30) controls both playback speed and export speed. The default of 12 fps matches Knowlton's original frame rate for BEFLIX animations.
Syntax Validation
When you click Render, the studio validates your script before generating frames. It checks for:
Unknown commands — Any command name not recognized by the interpreter.
Unmatched blocks — Missing END for REPEAT, DEF, or IF blocks, or orphan END statements without a matching opener.
Wrong argument count — Commands with fewer arguments than required.
Undefined subroutines — CALL referencing a subroutine name not defined with DEF.
If errors are found, the error count is shown on the Render button, the offending lines are highlighted red in the editor, and the debug info bar lists each error with its line number. Toggle the debug panel with the beetle icon button in the 1963 tab.
Audio
BEFLIX Studio supports importing audio tracks to score your animations, inspired by VanDerBeek’s Poemfield films which were scored by composers like John Cage. All audio UI is hidden until you import a track, keeping the interface clean.
Importing Audio
Click Import Audio in the Post FX tab to open a file picker and load an audio file (MP3, WAV, or OGG). Once loaded, the waveform appears below the canvas. To remove the track, click Remove in the Audio section.
Persistence: Your imported audio track, waveform, BPM, filter settings, and reactive toggle are saved automatically to your browser’s local storage (IndexedDB). When you reload the page, your audio is restored without needing to re-import the file.
Playback Sync
Audio plays in sync with your animation. When you press Play, audio starts at the current frame’s position. Pause stops audio. When the animation loops, audio restarts from the beginning.
Audio Scrubbing
When paused, stepping through frames with arrow keys plays a short (~100ms) audio snippet at each frame’s position, letting you hear exactly where you are in the track.
Period Filters
Three audio filters simulate vintage audio processing. All are combinable:
| Filter | Effect |
|---|---|
| Tape | Lowpass filter at 3.5kHz with resonance — warm, muffled sound like tape playback |
| Tube | Soft-clip waveshaper — gentle harmonic saturation |
| Crackle | Sparse noise impulses mixed in — vinyl surface noise |
Audio-Reactive Effects
Enable the Reactive checkbox in the Post FX tab to make visual effects respond to audio frequency content in real time:
| Effect | Driven by | Behavior |
|---|---|---|
| Bloom | Bass (20–300 Hz) | Blur radius, brightness, and intensity all surge on kick drums and bass hits |
| Scanlines | Treble (4–20 kHz) | Scanlines flicker in and out with hi-hats and cymbal transients |
| Grain | Mid (300–4000 Hz) | Film grain swells from subtle to heavy static on loud midrange content |
| Gel | Bass + Mid | Color gel wash pulses with combined low and mid energy |
Reactive values use adaptive range normalization — the system automatically adjusts to whatever dynamic range exists in your music, so any track with audible beats will produce visible effects.
When Reactive is off or no audio is loaded, effects use their standard hardcoded values.
BPM Markers
Enter a BPM value in the Post FX tab to display beat markers on the waveform. A helper text shows “1 beat = N frames” to help align animation events to musical beats.
Loop Audio
Enable Loop in the Post FX tab to repeat the audio track when it reaches the end during playback. The waveform display tiles to show the looped pattern. Loop state is saved with the project.
Export with Audio
When exporting to WebM with audio loaded, the audio track is muxed into the video file (including any active period filters). GIF export does not include audio.
Keyboard Shortcuts
These keyboard shortcuts are available when the editor has focus:
| Shortcut | Action |
|---|---|
Ctrl+Enter |
Render script |
Ctrl+S |
Save project to .beflix file |
Ctrl+G |
Locate — in editor: jump canvas to matching frame; on canvas: jump editor to matching line |
Ctrl+N |
New project — clears editor, canvas, and state |
Space |
Play / Pause |
Left Arrow |
Previous frame (or previous command in debug mode) |
Right Arrow |
Next frame (or next command in debug mode) |
Home |
Jump to first frame |
End |
Jump to last frame |
Editor Shortcuts
These shortcuts are active in the code editor:
| Shortcut | Action |
|---|---|
/ |
Open slash-command snippet menu |
Escape |
Close slash-command menu |
2026 Tab Shortcuts
These shortcuts are active on the 2026 tab:
| Shortcut | Action |
|---|---|
Enter |
Send message |
Shift+Enter |
New line in message |
Escape |
Cancel AI generation (while streaming) |
Tips & Recipes
Composition Techniques
Build Up Layers Between Frames
The grid persists between frames — draw, capture, draw more, capture again. Each frame shows the accumulated result of all drawing since the last CLEAR. This is fundamental to how BEFLIX works: the grid is a persistent canvas.
CLEAR 0
TEXT 100 40 "FIRST" 7 2
FRAME 12
TEXT 80 80 "SECOND" 5 2 ; adds to existing, doesn't replace
FRAME 12
TEXT 60 120 "THIRD" 3 2
FRAME 12
Use DISSOLVE for Smooth Transitions
The DISOLV command provides cinematic transition effects between scenes. Random dissolve (F) gives an organic, cinematic feel. Spiral inward (SI) creates dramatic reveals. Spiral outward (SO) grows a new scene from the center.
; Scene 1
TEXT 80 80 "SCENE ONE" 7 3
FRAME 24
; Transition
DISOLV 0 18 SI ; spiral to black
; Scene 2
CLEAR 0
TEXT 60 80 "SCENE TWO" 7 3
FRAME 24
Combine SCROLL + REPEAT for Scrolling Text
CLEAR 0
TEXT 20 80 "SCROLLING MESSAGE" 7 2
REPEAT 60
SCROLL -4 0 ; scroll left
FRAME 1
END
Think in 8 Levels — Contrast is Everything
With only 8 gray levels, every shade matters. Use 0 and 7 for maximum contrast. Use middle levels (3–5) for subtle detail and secondary elements. TRANSLAT can redistribute levels after drawing to increase or decrease contrast across the entire grid.
VanDerBeek's Techniques
Mosaic Textures
NOISE fills create rich texture fields. BLOW magnifies small areas into mosaic patterns. VanDerBeek used these as backgrounds for text overlays in his Poemfield films.
NOISE 0 0 252 184 2 6
SMOOTH
BLOW 0 0 252 184 3
FRAME 12
TEXT 60 80 "POETRY" 7 3
FRAME 24
Text in Noise
Draw text, then partially noise over it. This creates text emerging from or sinking into texture — a signature VanDerBeek effect.
TEXT 80 80 "EMERGE" 7 3
FRAME 12
NOISE 0 0 252 184 0 5 ; noise partially covers text
FRAME 12
GROW Halos
Seed a bright point, then GROW a ring around it. Multiple GROW passes create concentric rings radiating outward from the seed.
CLEAR 0
PAINT 126 92 1 1 7 ; bright seed
REPEAT 15
GROW 0 7 3 ; dark near bright → mid-gray
GROW 0 3 1 ; dark near mid → dark gray
FRAME 2
END
BLOW Cascades
Repeated BLOW magnification creates increasingly abstract textures as fine details are lost and replaced by blocky patterns.
TEXT 20 10 "DIGITAL" 7 1
REPEAT 4
BLOW 0 0 252 184 2
FRAME 12
END
Common Patterns
Fade In from Black
Use TRANSLAT to progressively remap levels from black to their target values, creating a fade-in effect:
CLEAR 0
; draw your scene...
TEXT 80 80 "TITLE" 7 3
PAINT 40 40 172 100 5
; ...then capture with fade
TRANSLAT 0 0 0 0 0 0 0 0 ; everything → black
FRAME 1
TRANSLAT 0 0 0 0 1 1 1 1
FRAME 2
TRANSLAT 0 1 1 2 2 3 3 4
FRAME 2
TRANSLAT 0 1 2 3 4 5 6 7 ; identity (full brightness)
FRAME 24
Color Cycling Loop
Shift all levels by one position each frame to create a cycling, pulsing animation:
TEXT 80 80 "PULSE" 7 3
NOISE 0 0 252 184 1 6
FRAME 6
REPEAT 30
TRANSLAT 1 2 3 4 5 6 7 0 ; cycle all levels
FRAME 2
END
Diamond Growth from Center
A single bright pixel at the center, expanded by GROW, naturally forms a diamond shape:
CLEAR 0
PAINT 126 92 1 1 7
REPEAT 40
GROW 0 7 7
FRAME 1
END
; Result: expanding diamond shape
Strobe Flash
Rapidly alternate all levels between two extremes for a strobe effect:
REPEAT 10
TRANSLAT 0 7 0 7 0 7 0 7
FRAME 1
TRANSLAT 7 0 7 0 7 0 7 0
FRAME 1
END
Wave Distortion
Use COLUM to shift columns in opposite directions, creating a wave-like distortion of existing content:
TEXT 40 80 "WAVE" 7 4
FRAME 12
REPEAT 30
COLUM 0 126 U 3
COLUM 126 126 D 3
FRAME 1
END
Faithful Recreation
BEFLIX Studio aims to be as historically accurate as possible while remaining usable in a modern browser. This section documents what is original, what we changed, and what we added.
Sources
The implementation is based on the following primary sources:
- Ken Knowlton, “BEFLIX, A Programming Language for Producing Animated Diagram Movies” — Bell Labs Technical Memorandum MM-63-1271-6, June 17, 1963. The original BEFLIX specification describing the macro-instruction set, the 2DAL6 language substrate, the bug/surface system, transliteration tables, and the SC-4020 output pipeline.
- Ken Knowlton, “A Computer Technique for Producing Animated Movies” (1964) — the published AFIPS paper covering the language and its use.
- Ken Knowlton & Leon Harmon, “Computer-Produced Grey Scales” (1972) — details on the 8-level gray scale system.
- Stan VanDerBeek & Ken Knowlton, Poem Field series (1966–1969) — frame-by-frame study of the surviving films, particularly Nos. 1, 2, 3, and 7.
- Knowlton's notes and interviews on the BEFLIX command set, scanner system, and collaboration with VanDerBeek.
What is 100% Faithful
- 8 gray levels — 0 (black) through 7 (brightest), the same quantization as the original. Knowlton mapped these to specific Hollerith characters on the SC-4020; we map them to pixel intensities.
- Command spellings —
DISOLV,STRECH,COLUM,RETREV,TRANSLATall preserve Knowlton's original abbreviations from the 1963 tech memo. - Core drawing commands — PAINT, LINE, BORDER, ARC, COPY, and TEXT (Knowlton's TYPE) were all in the 1963 specification. Our versions are simplified — the originals used bug-defined regions and writing modes — but the operations are the same.
- Transforms — TRANSLAT, GROW, DISOLV, ROTATE, STRECH (Knowlton's EXPAND), PRESS (Knowlton's SQUASH), ZOOMIN, and REDUCE all appeared in the 1963 tech memo and behave as described.
- 12 fps default — Knowlton's original frame rate for the SC-4020 microfilm output.
- No-undo grid — every command permanently modifies the grid, exactly as on the IBM 7094. The accumulative, palimpsest quality of BEFLIX compositions depends on this constraint.
- Dissolve patterns — the five dissolve patterns (F=random, SI=spiral in, SO=spiral out, R=wipe right, L=wipe left) match those described in the 1963 specification.
What We Changed
- Grid resolution — the original BEFLIX grid was 126×108 (constrained by the SC-4020 typewriter mode, where each cell was a single 6-bit character). Ours is 252×184 — roughly double the resolution. This was a deliberate creative choice to give modern users more detail to work with.
- Bugs → direct coordinates — the original used “bugs” (named two-letter pointers like AA, BB, … ZZ) positioned on surfaces to define rectangular regions. Every drawing command referenced a pair of bugs (top-right + bottom-left) rather than explicit x,y,w,h coordinates. We replaced this with direct coordinate arguments and single-letter scanners (A–Z) for simplicity.
- Single surface — the original had four independent drawing surfaces (WW, XX, YY, ZZ), allowing layering and cross-surface compositing. We use a single surface.
- Transliteration tables — the original maintained
10 persistent transliteration tables (numbered 1–10), each mapping all
64 possible 6-bit character values. Our
TRANSLATtakes 8 inline values (one per gray level) — simpler but less powerful. - Writing modes — the original had three writing modes: WRITE (replace), AND (logical AND), and OR (logical OR). These applied to PAINT, BORDER, LINE, ARC, COPY, and other commands, enabling masking and compositing. We support WRITE mode only.
- Dissolve granularity — the original dissolved in 6×6 sub-areas, producing a chunky, pixelated transition characteristic of the Poem Field films. Ours dissolves per-pixel, which is smoother but less authentic.
- Input method — the original used punch cards fed to the IBM 7094. We use a text editor with syntax highlighting. The command syntax is preserved; only the input medium changed.
- Rendering pipeline — the original rendered to 35mm film via the Stromberg-Carlson SC-4020 microfilm recorder. We render to an HTML canvas. The SC-4020 render effect simulates the look of the original output.
- Playback — original films were viewed as projected 35mm film. We provide real-time playback with adjustable frame rate (1–30 fps).
- Modern aliases —
DISSOLVEis accepted as an alias forDISOLVwith the random pattern.READis accepted forRETREV. The original spellings always work.
What the Original Had That We Don’t
- TRACK — a turtle-graphics command for drawing curves from directional steps (U, D, L, R, N, S, E, W). The bug follows the path, drawing with a specified character, width, mode, and speed. Important for organic shapes in the original films.
- XPORM — a 31-level time-contour morphing command that produced animated transitions between two shapes. Arguably the most visually distinctive BEFLIX feature we don’t have.
- JUSTIF — justify/fit material from one rectangle into another by stretching or compressing to fit.
- AND / OR writing modes — compositing modes that applied logical AND or OR between old and new values, enabling masking and transparency effects. See “What We Changed” above.
- Four surfaces — independent drawing layers (WW, XX, YY, ZZ) for compositing. See “What We Changed” above.
- CURVE7 — BCI-encoded curve path descriptions (low priority — TRACK covers the concept).
- PLACE / BUGTL — bug positioning and transliteration table setup commands. Not needed with our direct-coordinate and inline-TRANSLAT approach.
What We Added
- New drawing commands — CIRCLE (the original could approximate circles with ARC 0–360), NOISE (random fill), SMOOTH (2×2 averaging), BLOW (mosaic magnification inspired by SC-4020 halftone), FADE (gradual interpolation to a target level), INVERT (shortcut for TRANSLAT 7 6 5 4 3 2 1 0), and CLEAR (shortcut for painting the entire grid).
- Flow control — REPEAT loops, IF/IFANY/IFALL/IFNONE conditionals, DEF/CALL named subroutines, and AREA named regions. The original had conditionals built into specific commands (ARC, TRACK, GROW) and used the PAP/2DAL6 macro system for reuse; we expanded these into general-purpose programming constructs.
- Scanner enhancements — CONFINE/FREE (restrict a scanner to an area) and scanner conditionals (IFANY, IFALL, IFNONE). The original bugs did not have explicit confinement.
- COLUM — cyclic column shifting. While the original had ROTATE for cyclic region shifting, COLUM as a distinct column-band operation is our addition.
- Color palettes — the original was strictly grayscale. Our palette system maps 8 gray levels to 8 RGB colors, applied at render time. This mirrors VanDerBeek's post-production colorization with gels and optical printing, but makes it interactive.
- Render effects — CRT phosphor, scanlines, halftone, mosaic, and gel overlay effects. These simulate various display technologies; the underlying grid remains grayscale.
- Guide panel — a slide-out reference panel accessible from the header. The original had no inline help.
- AI assistant — natural language film generation. Entirely new.
- Export — WebM video and GIF export. The original output was physical film.
- Audio — audio import and reactive visual effects. The original BEFLIX had no audio capabilities, though Bell Labs was simultaneously pioneering computer music with Max Mathews down the hall.
The Authentic Experience
If you want to experience BEFLIX as close to the original as possible:
- Use the SC-4020 render mode — this simulates the phosphor characteristics of the Stromberg-Carlson microfilm recorder.
- Use the Monochrome (grayscale) palette — no color, just 8 shades of gray as Knowlton intended.
- Enable Scanlines for the CRT look.
- Set the frame rate to 12 fps (the default).
- Write code only — don't use the AI. Type your commands in the 1963 tab and render. This is the closest you can get to the punch-card workflow: write instructions, submit them, watch the result.
- Stick to commands from the 1963 specification: PAINT, LINE, BORDER, ARC, TEXT, COPY, SCROLL, TRANSLAT, GROW, DISOLV, ROTATE, STRECH, PRESS, ZOOMIN, REDUCE, FRAME, and the scanner commands (SET, MOVE, WRITE, RETREV). Avoid our additions: CIRCLE, NOISE, SMOOTH, BLOW, FADE, INVERT, CLEAR, COLUM, DEF/CALL, AREA, and the IF conditionals.
- Embrace the constraint: no undo, no preview, no interactive drawing. Build compositions through accumulation and transformation. Let happy accidents happen. This is the aesthetic that made the Poem Field films what they are.
FAQ
My NOISE pattern looks different every time I render. What happened?
The NOISE command uses random values, and it produces a
different pattern every time the script renders. So when
you edit code on the same frame as a NOISE command, the noise regenerates
with new random values, which can make the result look unexpected.
NOISE is our addition (it was not in the 1963 BEFLIX specification), but the non-deterministic behavior is consistent with how the IBM 7094 would have handled random operations. To work around it:
- Capture the noise first. Add a
FRAMEcommand right after theNOISE, then draw your shapes on subsequent frames. The noise is now frozen and won't change on re-render. - Embrace the randomness. VanDerBeek treated NOISE as a generative texture — each run produced a unique variation. The unpredictability was part of the aesthetic.