240 independent oscillators, one per even scanline. Each moves at exactly one pixel per frame and turns around at ±0.75q from center. That is the whole trick, and it is worth being clear that there is no spiral anywhere in the code. The amplitude grows with q but the speed does not, so row q has a period of about 3q frames: row 1 turns around every 3 frames, row 240 every 720. All 240 start together at center moving left, so the turnaround sweeps down the screen as a straight diagonal, and then the phases smear apart and the braid appears. The spiral is emergent. Tick "sinusoidal motion" to give the rows cosine easing, a real rotating cylinder, and the figure reads as more physically honest and much less interesting: the hard chevron creases go away. Tick "flat color" to drop the two opposed brightness ramps and the figure loses its near/far face entirely and becomes directionally ambiguous. Edge cases, as written: q=240 addresses row 480, one past the bottom, and its right-hand turning point is x=360, one past the right edge. Both are clipped rather than wrapped here.
A sine ribbon: for each row, a horizontal band centered on 180 + q/2·sin(q/20 + c), drawn four times at widths q/4, q/5, q/6 and q/17 in increasing brightness, so it comes out shaded like a tube. And this is the smarter of the two files. It erases selectively, repainting the previous frame's ribbon in color 0 at the q div 4 width only, which is the widest of the four passes and therefore covers all of them. A correct, cheap, targeted erase: a few thousand bytes instead of 172,800. In the next one I threw that away.
The mirrored top half is added, and to make that work the selective erase is replaced by clear_vga_screen, the whole 172,800 bytes, every frame. The mirror is a true 180° rotation about (180,240) rather than a vertical flip, which is the same symmetry NEWWAVE.PAS reaches for four days later. Two edge artifacts: row 240 is never written because q starts at 1, so a one-pixel seam runs across the middle; and q=240 addresses row 480, one scanline past the end. The phase advances a whole radian per frame. sin(q/20) has a wavelength of about 126 in q, so a radian is roughly a sixth of a wavelength per frame, too fast to read as motion, and it strobes. Pull the phase-step slider down to about 0.10 and the ribbon becomes easier to see.
1996-03-27 17:32 · 788 bytes · With the sine initializer.
uses crt,jmodex;var q:integer;a:array[1..240]of integer; b,c:array[1..240]of byte; begin if set_vga_modex(7,360,480,1)=0 then halt(0);clear_vga_screen(0); for q:=1 to 64 do set_dac_register(q,0,0,q); randomize; for q:=1to 240do a[q]:=180+round(10*sin(q/30)); for q:=1to 240do b[q]:=0; repeat repeat until(port[$3da]and 8)=0;repeat until(port[$3da]and 8)<>0; for q:=1to 240do draw_line(a[q],q*2,a[q],q*2,0); for q:=1to 240do if b[q]=0then dec(a[q]) else inc(a[q]); for q:=1to 240do draw_line(a[q],q*2,a[q],q*2,c[q]); for q:=1to 240do begin if((a[q]<=round(180-q*0.75))or(a[q]>=round(180+q*0.75)))then b[q]:=1-b[q]; if b[q]=0then c[q]:=63-((abs(180-a[q]))div 12) else c[q]:=33+(abs(180-a[q])div 12); end; until keypressed;asm mov ah,0;mov al,3;int 16;end;end.
1996-03-27 17:37 · 768 bytes · Without it.
uses crt,jmodex;var q:integer;a:array[1..240]of integer; b,c:array[1..240]of byte; begin if set_vga_modex(7,360,480,1)=0 then halt(0);clear_vga_screen(0); for q:=1 to 64 do set_dac_register(q,0,0,q); randomize; for q:=1to 240do a[q]:=180; for q:=1to 240do b[q]:=0; repeat repeat until(port[$3da]and 8)=0;repeat until(port[$3da]and 8)<>0; for q:=1to 240do draw_line(a[q],q*2,a[q],q*2,0); for q:=1to 240do if b[q]=0then dec(a[q]) else inc(a[q]); for q:=1to 240do draw_line(a[q],q*2,a[q],q*2,c[q]); for q:=1to 240do begin if((a[q]<=round(180-q*0.75))or(a[q]>=round(180+q*0.75)))then b[q]:=1-b[q]; if b[q]=0then c[q]:=63-((abs(180-a[q]))div 12) else c[q]:=33+(abs(180-a[q])div 12); end; until keypressed;asm mov ah,0;mov al,3;int 16;end;end.
1996-03-27 18:33 · 801 bytes · Selective erase.
uses crt,jmodex;var c,q:integer;a:array[1..240]of integer; begin if set_vga_modex(7,360,480,1)=0 then halt(0);clear_vga_screen(0); for q:=1 to 64 do set_dac_register(q,0,0,q); for q:=1to 240do a[q]:=round(180+q/2*sin(q/20)); c:=0; repeat repeat until(port[$3da]and 8)=0;repeat until(port[$3da]and 8)<>0; inc(c);delay(10); for q:=1to 240do begin draw_line(a[q]-(q div 4),240+q,a[q]+(q div 4),240+q,0);end; for q:=1to 240do a[q]:=round(180+q/2*sin(q/20+c)); for q:=1to 240do begin draw_line(a[q]-(q div 4),240+q,a[q]+(q div 4),240+q,16); draw_line(a[q]-(q div 5),240+q,a[q]+(q div 5),240+q,32); draw_line(a[q]-(q div 6),240+q,a[q]+(q div 6),240+q,48); draw_line(a[q]-(q div 17),240+q,a[q]+(q div 17),240+q,63); end; until keypressed;asm mov ah,0;mov al,3;int 16;end;end.
1996-03-27 18:48 · 981 bytes · Mirrored, and clearing everything.
uses crt,jmodex;var c,q:integer;a:array[1..240]of integer; begin if set_vga_modex(7,360,480,1)=0 then halt(0);clear_vga_screen(0); for q:=1 to 64 do set_dac_register(q,0,0,q); for q:=1to 240do a[q]:=round(180+q/2*sin(q/20));c:=0; repeat repeat until(port[$3da]and 8)=0;repeat until(port[$3da]and 8)<>0; inc(c);clear_vga_screen(0); for q:=1to 240do begin draw_line(360-a[q]+(q div 4),240-q,360-a[q]-(q div 4),240-q,16); draw_line(360-a[q]+(q div 5),240-q,360-a[q]-(q div 5),240-q,32); draw_line(360-a[q]+(q div 6),240-q,360-a[q]-(q div 6),240-q,48); draw_line(360-a[q]+(q div 17),240-q,360-a[q]-(q div 17),240-q,63); draw_line(a[q]-(q div 4),240+q,a[q]+(q div 4),240+q,16); draw_line(a[q]-(q div 5),240+q,a[q]+(q div 5),240+q,32); draw_line(a[q]-(q div 6),240+q,a[q]+(q div 6),240+q,48); draw_line(a[q]-(q div 17),240+q,a[q]+(q div 17),240+q,63);end; for q:=1to 240do a[q]:=round((180+q/2*sin(q/20+c))); until keypressed;asm mov ah,0;mov al,3;int 16;end;end.