lignes.roomates.ts

a sample implementation for a lignes model

import { EtchModel, Grain, Palette } from './utils';

const Token = {
  pixelDensity: 5,
  strokeWeight: 5,
  pointVariance: 0.05,
  lineSegments: 20,
  numberOfLines: 5,
  shouldUseFuzzyGrain: false,
  shouldUseScaledColors: false,
};

export const Roomates: EtchModel = {
  meta: {
    title: 'roomates',
    description:
      'several shapes fighting for their space on the canvas. a metaphor for internal conflict, or roomates.',
    stability: 'development',
    aspectRatio: {
      width: 3,
      height: 4,
    },
  },
  render: ({ p, log, done, width, height }) => {
    const palette = new Palette();
    const grain = Grain.withShader(p);
    const background_color = '#fff2e4';

    // decide random values
    Token.lineSegments = p.random([4, 20, 80]);
    Token.numberOfLines = p.random([4, 5, 8, 16, 80]);
    Token.shouldUseFuzzyGrain = Boolean(p.random() < 0.9);
    Token.shouldUseScaledColors = Boolean(p.random() < 0.6);

    log(Token);

    const getColor = Token.shouldUseScaledColors
      ? () => palette.getScaledColor({ exclude: [background_color] })
      : () => palette.getColor({ exclude: [background_color] });

    p.setup = () => {
      const c = p.createCanvas(width, height);
      p.pixelDensity(Token.pixelDensity);

      // no need to setup
      if (!Token.shouldUseFuzzyGrain) {
        grain.setup(c);
      }
    };

    p.draw = () => {
      const segments = Token.lineSegments;
      const numberOfLines = Token.numberOfLines;
      const quarterHeight = p.height / numberOfLines;
      p.background(getColor());

      for (let i = 0; i < numberOfLines; i++) {
        const y = quarterHeight * i + quarterHeight / 2;

        drawSquigglyLine({
          start: {
            x: 0,
            y,
          },
          end: {
            x: p.width,
            y: p.randomGaussian(y),
          },
          segments,
        });
      }

      p.noLoop();

      // draw border around
      p.noFill();
      p.stroke('black');
      p.strokeWeight(12);
      p.beginShape();
      p.vertex(0, 0);
      p.vertex(p.width, 0);
      p.vertex(p.width, p.height);
      p.vertex(0, p.height);
      p.vertex(0, 0);
      p.endShape();

      if (Token.shouldUseFuzzyGrain) {
        Grain.withFuzzification(p, 20);
      } else {
        grain.apply();
      }

      done();
    };

    type SquigglyLineOptions = {
      start: {
        x: number;
        y: number;
      };
      end: {
        x: number;
        y: number;
      };
      segments: number;
    };

    function drawSquigglyLine(options: SquigglyLineOptions) {
      const { start, end, segments } = options;
      const { x: x1, y: y1 } = start;
      const { x: x2, y: y2 } = end;

      p.strokeWeight(Token.strokeWeight);
      p.noFill();

      const lengthOfSegment = (x2 - x1) / segments;
      const heightOfSegment = (y2 - y1) / segments;
      const points = [];

      for (let i = 0; i < segments; i++) {
        const x = x1 + lengthOfSegment * i;
        const y =
          (y1 + heightOfSegment * i) * p.randomGaussian(1, Token.pointVariance);
        p.point(x, y);
        points.push({ x, y });
      }
      points.push({ x: x2, y: y2 });

      p.fill(getColor());
      p.beginShape();
      p.curveVertex(x1, y1);
      for (const point of points) {
        p.curveVertex(point.x, point.y);
      }
      p.curveVertex(x2, y2);
      p.vertex(p.width, p.height);
      p.vertex(0, p.height);
      p.vertex(x1, y1);
      p.endShape();
    }
  },
};