Optical illusion: are these lines parallel or not?

Hello, I joined recently the forum.

I’ve decided to share some of my sketches which, I believe, some may find interesting.

From time to time, I like wandering the Internet to look for ideas on maths and arts. I came across this optical illusion in a Tumblr blog and I decided to make a sketch out of it. This is a gif with the result; you can find the code below to run the animation endlessly.


main sketch
Intent to reproduce the following optical illusion: 
 The animation loops forever with a period set
 via the variable 'duration_secs'.
 The image can be divided into rows of squares,
 some of which move, while other don't.
 The visual part (render, colours, etc.) is managed
 by the class 'Row'; on the other hand, the dynamic
 of the mobile rows are carried out by the class 'DynSyst'.
Row[] rows;
int q_rows;
int q_squares; // squares per row
float edge; // edge of the squares
float duration_secs; // duration of the animation, in secs
DynSyst sd;

void setup() {
  size(640, 480);

  rectMode(CENTER); // important

  duration_secs = 6; // 6 seconds
  edge = 80;
  q_rows = int(height / edge) + 1;
  q_squares = int(width / edge) + 5;

  float cx_ini = -2 * edge; // abscissa of all rows' position

  sd = new DynSyst(cx_ini, 3.f * edge / 4, duration_secs);
  rows = new Row[q_rows];
  for (int i = 0; i < rows.length; i++) {
    rows[i] = new Row(cx_ini, i * edge, edge, q_squares);
    rows[i].is_mobile = i % 2 == 0 ? false : true;

void draw() {
  for (int i = 0; i < rows.length; i++) {
class for the motion bits
Class representing a (discrete) simple harmonic motion (SHM).
 A simple harmonic motion is a sort of periodic motion,
 which is described by a sinusoidal function.
 This class will be using this one:
 x(t) = A * sin(w * t + a)
 -A is the amplitude of the motion.
 -w is the angular velocity, calculated as w = 2 * PI / T.
 -T is the motion's period, in seconds.
 -a is the initial phase, which we'll take as 0.
 By <em>discrete</em>, it is meant that the time variable
 changes in a discrete manner, instead of continuously.
 In each iteration the time variable's value is incremented
 by a fixed value.
 This fixed value is related to the sketch's frameRate
 and guarantees that, if the dynamical system's 'iterate()'
 method is called once per frame, the animation has period T.
class DynSyst {
  final float DELTA_T = 1.f / frameRate; // time increment per iteration
  private float cx; // center or equilibrium point of the SHM
  float x; // position at time t
  float amplitude;
  float period;
  float ang_vel;
  float t;

  DynSyst(float cx, float amplitude, float period_secs) {
    this.cx = x = cx;
    this.amplitude = amplitude;
    period = period_secs;
    ang_vel = 2 * PI / period;
    t = 0.f;

  /*Increments dynamical system's time variable
   and returns the position at this new time.*/
  float iterate() {
    t += DELTA_T;
    if (t >= period) {
      t = 0.f;
    x = cx + amplitude * sin(ang_vel * t);

    return x;
class for the visual bits
Class representing a row of squares with alternating colours.
 The row's position is the center of its first (left-most) square.
class Row {
  private float cx_ini; // row's initial abscissa
  float cx, cy; // row's current position
  float edge;
  int q_squares; // quantity of squares
  color c1 = #ffffff, c2 = #000000; // colours to alternate between
  boolean is_mobile;

  Row(float cx, float cy, float edge, int q_squares) {
    this.cx = cx_ini = cx;
    this.cy = cy;
    this.edge = edge <= 0.f ? 0.f : edge;
    this.q_squares = q_squares <= 0 ? 0 : q_squares;
    is_mobile = false;

  void update(float cx) {
    if (is_mobile) {
      this.cx = cx;

  /*Draws this row alternating the colour of the squares.
  Assumes rectMode(CENTER) has been set.*/
  void draw() {
    color c;

    c = c1;
    for (int i = 0; i < q_squares; i++) {
      draw_square(cx + i * edge, cy, edge, c);
      c = c == c1 ? c2 : c1;

  /*Draws a square given its center, edge and colour.
   Assumes rectMode(CENTER) has been set.*/
  private void draw_square(float cx, float cy, float edge, color c) {
    rect(cx, cy, edge, edge);

Feel free to make any comments, suggestions or even post back your tinkers.