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.

Tip The editor auto-renders when you click away from the code area, so you can edit code, then click Play without needing to Render first. Scripts also auto-render on page load.
Tip The full script above is a complete BEFLIX animation. Every BEFLIX program follows this pattern: draw, capture, transform, capture, repeat.

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.

Tip Press 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.

Tip Slash-command filtering is case-insensitive. Typing /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.

0
1
2
3
4
5
6
7

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
Note 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 pixels
  • h — height in pixels
  • level — gray level (0=black, 7=white)

Fill a rectangle at position (xy) 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 coordinates
  • x2, y2 — end point coordinates
  • level — gray level (0–7)

Draw a straight line from (x1y1) to (x2y2) 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 coordinates
  • r — radius in pixels
  • level — gray level (0–7)
  • FILL — optional keyword; fill the circle solid

Draw a circle centered at (cxcy) 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
Note 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 coordinates
  • r — radius in pixels
  • start — start angle in degrees (0 = 3 o'clock)
  • end — end angle in degrees, measured clockwise
  • level — gray level (0–7)
  • FILL — optional keyword; draw a filled wedge

Draw an arc centered at (cxcy) 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 (xy) 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 position
  • w, h — outer dimensions of the border rectangle
  • thickness — border width in pixels
  • level — 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 copy
  • dx, 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)
Tip Combine 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 position
  • w, h — region dimensions
  • min, 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]
  • t0t7 — eight target levels: pixels at level 0 become t0, level 1 becomes t1, … level 7 becomes t7
  • x, 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
Tip 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 change
  • ns2 — neighbor level: the candidate must have at least one cardinal neighbor (up/down/left/right) at this level
  • ns3 — result level: matching candidates become this level
  • x, 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
Tip 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
Note Apply 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 region
  • w, h — region dimensions
  • factor — 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
Tip 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 region
  • w, h — region dimensions
  • factor — 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 region
  • w, h — region dimensions
  • factor — 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 region
  • w, h — region dimensions
  • H|V — axis: H for horizontal stretch, V for vertical stretch
  • factor — 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 region
  • w, h — region dimensions
  • H|V — axis: H for horizontal compress, V for vertical compress
  • factor — 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 position
  • w — width of the column range to shift
  • U|D — direction: U shifts up, D shifts down
  • amount — 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 region
  • w, h — region dimensions
  • U|D|L|R — direction: U up, D down, L left, R right
  • amount — 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 transition
  • x, 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
Tip
Conditionals only work with scanners. You must SET a scanner position, READ the grid value, then test it. There is no general-purpose IF — all conditions test the grid through scanner eyes.

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
Tip
Always 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
UUp
DDown
LLeft
RRight
URUp-Right (diagonal)
ULUp-Left (diagonal)
DRDown-Right (diagonal)
DLDown-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.

Important
Always 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
Tip
CONFINE is essential for controlled scanner animations. Without it, scanners can walk off the grid edges and produce unexpected results.

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 position
  • w, 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
Tip
Subroutines are especially powerful with AREA — define an area, then write subroutines that operate on it. Change the area definition and all subroutines update automatically.

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.

Tip The 2026 tab never bypasses the code. When the AI generates a script, it goes straight into the editor — you can read it, modify it, learn from it. The code is always authoritative.

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.

Note If you have both an AI key and a personal API key configured, the AI key takes priority when the AI Key option is selected.

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 subroutinesCALL 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:

FilterEffect
TapeLowpass filter at 3.5kHz with resonance — warm, muffled sound like tape playback
TubeSoft-clip waveshaper — gentle harmonic saturation
CrackleSparse 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:

EffectDriven byBehavior
BloomBass (20–300 Hz)Blur radius, brightness, and intensity all surge on kick drums and bass hits
ScanlinesTreble (4–20 kHz)Scanlines flicker in and out with hi-hats and cymbal transients
GrainMid (300–4000 Hz)Film grain swells from subtle to heavy static on loud midrange content
GelBass + MidColor 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
Tip
The best way to learn BEFLIX is to browse the Examples tab, study how the example programs work, and copy them to your editor to modify. Start with the Techniques example for a comprehensive sampler of every command. You can also use the 2026 tab to describe what you want to create in plain English — the AI writes the code for you, and you can study what it produced to learn how commands work together.

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 spellingsDISOLV, STRECH, COLUM, RETREV, TRANSLAT all 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 TRANSLAT takes 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 aliasesDISSOLVE is accepted as an alias for DISOLV with the random pattern. READ is accepted for RETREV. 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 FRAME command right after the NOISE, 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.
BEFLIX DOCS