Flexible Motion Grid
Flexible motion grid is a generative design system that reinvents one of the most mundane computer actions since its invention: dragging rectangles to select items. The tool explores how such repetitive shapes can be used to create information and patterns in motion. The tool uses a symmetrical grid where a quadrilateral of any dimension can be drawn with different attributes and text inputs.
Flexible Motion Grid: Transformation
The transformation o Flexible Motion Grid is a moving object along a quadrilateral path, which is constantly recalculated according to its dimensions. Its dimensions are moved by a dragging effect with the mouse. The motion path calculation for the moving object starts when the mouse is clicked on the canvas and ends when it is released
Relevating coding functions for a grid transformation
var drawThings;
var initX, initY;
var posX, posY;
var globalSpeed = 3;
var baseSpeed = globalSpeed;
var Yspeed = globalSpeed;
var Xspeed = globalSpeed;
var rectWidth, rectHeight;
var minX, minY;
var maxX, maxY;
function setup() {
createCanvas(600, 600);
noFill();
strokeWeight(4);
stroke(255);
}
function draw() {
background(0);
if (drawThings) {
init();
}
push()
noStroke()
fill(255,0,0)
ellipse(mouseX, mouseY, 20)
pop()
}
function mousePressed() {
drawThings = !drawThings;
initX = mouseX;
initY = mouseY;
posX = initX;
posY = initY;
}
function mouseReleased() {
initX = mouseX;
initY = mouseY;
}
function init() {
// var distVar = dist(initX,initY, mouseX,mouseY)
rectWidth = mouseX - initX;
rectHeight = mouseY - initY;
rect(initX, initY, rectWidth, rectHeight);
minX = initX;
minY = initY;
maxY = rectHeight + initY;
maxX = rectWidth + initX;
if (rectWidth >= 50) {
if (rectHeight >= 50) {
// first speed horizontal
Yspeed = 0;
posX = posX + baseSpeed;
posY = posY + Yspeed;
// when value is bigger or same as maxX, stop moving X and move Y.
if (posX >= maxX) {
Yspeed = globalSpeed;
posX = maxX;
posY = posY + Yspeed;
baseSpeed = 50;
}
// when Y is bigger or same as Y, stop the base Speed,
if (posY >= maxY) {
baseSpeed = 0;
Xspeed = -globalSpeed;
posX = posX + Xspeed;
posY = maxY;
}
//
if (Xspeed == -globalSpeed && posY < maxY) {
Yspeed = 50;
posY = maxY;
}
//
if (posX <= minX) {
baseSpeed = 0;
Xspeed = 0;
posY = posY - globalSpeed;
}
//
if (posY <= minY) {
Xspeed = globalSpeed;
baseSpeed = 0;
posX = posX + Xspeed;
}
}
}
if (rectWidth < -1) {
if (rectHeight < -1) {
Yspeed = 0;
posX = posX - baseSpeed;
posY = posY + Yspeed;
// when value is bigger or same as maxX, stop moving X and move Y.
if (posX <= maxX) {
Yspeed = -globalSpeed;
posX = maxX;
posY = posY + Yspeed;
baseSpeed = 50;
}
// when Y is bigger or same as Y, stop the base Speed,
if (posY <= maxY) {
baseSpeed = 0;
Xspeed = +globalSpeed;
posX = posX + Xspeed;
posY = maxY;
}
if (Xspeed == globalSpeed && posY < maxY) {
Yspeed = 50;
posY = maxY;
}
if (posX >= minX) {
baseSpeed = 0;
Xspeed = 0;
posY = posY + globalSpeed;
}
}
}
ellipse(posX, posY, 50);
}
Flexible Motion Grid: Parameters
The parameters are independently applied to each new quadrilateral, instead of being applied to all of them. Thus, for each new quadrilateral, new parametric values can be chosen. The parameters are velocity, grid scale, width spacing, height spacing, shear factor, type/shape, rainbow/solid color, and pattern size. Below are examples of the parameters type/shape and grid scale. In the example below is a sketch that shows different grids with different parametric values for the size. The code displays a small fraction of the whole program.
Relevating coding functions for a grid transformation
var globalScale = 25;
function setup() {
sliderScale = createSlider(1, 4, 1, 1);
sliderScale.addClass("sliders");
sliderScale.parent("sliderGridScale");
}
function draw() {
grid = globalScale;
var gridOffset = grid / 1;
if (chk1.checked) {
displayGrid();
}
}
function displayGrid() {
push();
stroke(100);
strokeWeight(1);
while (l < width || l < height) {
line(0, l, width, l);
line(l, 0, l, height);
l += grid;
}
pop();
}
function newBlock() {
let scale = sliderScale.value();
}
Flexible Motion Grid: Iterations
Below are shown several iterations of Flexible Motion Grid. Each iteration was a step towards a the fully functional generative system. Below are recorded iterations. The code displays an example of a single interation, where the code was built on top of the core transformation, creating a more complete system overtime.
Relevating coding functions
class MovingShape {
constructor(globalSpeed) {
this.globalSpeed = globalSpeed;
this.baseSpeed = this.globalSpeed;
this.Yspeed = this.globalSpeed;
this.Xspeed = this.globalSpeed;
this.rectWidth = 0;
this.rectHeight = 0;
this.margin = 5;
this.patternDensity = 10;
this.lineSpeed = 1;
this.lineY;
this.triggerOffset = 25;
this.isDragging = false;
}
initShape() {
if (this.isDragging) {
this.init();
}
}
shapePressed() {
this.isDragging = true;
this.initX = mouseX;
this.initY = mouseY;
this.posX = this.initX;
this.posY = this.initY;
this.lineY = this.initY;
}
shapeReleased() {
this.isDragging = false;
this.globalSpeed = this.globalSpeed;
this.baseSpeed = this.globalSpeed;
}
init() {
this.rectWidth = mouseX - this.initX;
this.rectHeight = mouseY - this.initY;
this.minX = this.initX;
this.minY = this.initY;
this.maxY = this.rectHeight + this.initY;
this.maxX = this.rectWidth + this.initX;
}
moveInside() {
if (
this.rectWidth >= this.triggerOffset &&
this.rectHeight >= this.triggerOffset
) {
this.lineY = this.lineY + this.lineSpeed;
if (this.lineY > this.maxY) {
this.lineY = this.minY;
}
}
}
moveShape() {
// if the dragged values are higher than the trigger value in the constructor, activate the movement
if (
this.rectWidth >= this.triggerOffset &&
this.rectHeight >= this.triggerOffset
) {
this.Yspeed = 0;
this.posX += this.baseSpeed;
this.posY += this.Yspeed;
// if the X value is greater than maxX, stop X value and make Y value move
if (this.posX >= this.maxX) {
this.Yspeed = this.globalSpeed;
this.posX = this.maxX;
this.posY += this.Yspeed;
// very imporant! if the rect size gets bigger, the moving object readjusts with the baseSpeed
this.baseSpeed = 100;
}
if (this.posY >= this.maxY) {
this.baseSpeed = 0;
this.Xspeed = -this.globalSpeed;
this.posX += this.Xspeed;
this.posY = this.maxY;
}
if (this.Xspeed === -this.globalSpeed && this.posY < this.maxY) {
// very imporant! if the rect size gets bigger, the moving object readjusts with the baseSpeed
this.Yspeed = 100;
this.posY = this.maxY;
}
if (this.posX <= this.minX) {
this.baseSpeed = 0;
this.Xspeed = 0;
this.posY -= this.globalSpeed;
}
if (this.posY <= this.minY) {
this.Xspeed = this.globalSpeed;
this.baseSpeed = 0;
this.posX += this.Xspeed;
}
}
}
displayShape() {
push();
fill(255, 0, 0);
noStroke();
ellipse(this.posX, this.posY, 10);
pop();
}
displayInside() {
stroke(255);
strokeWeight(2);
//line(this.minX + 25, this.lineY, this.maxX - 25, this.lineY);
noStroke();
textSize(50);
fill(255);
// textAlign(CENTER)
// text("The quick brown fox jumps over the lazy dog", this.minX + (this.rectWidth / 2), this.minY + (this.rectHeight / 2)+25)
textAlign(LEFT);
text(
"The quick brown fox jumps over the lazy dog",
this.minX + 25,
this.minY + 25,
this.rectWidth - 25,
this.rectHeight - 25
);
}
displayRectangle() {
noFill();
strokeWeight(2);
stroke(255);
rect(this.initX, this.initY, this.rectWidth, this.rectHeight);
}
drawPattern() {
push();
rectMode(CENTER);
noStroke();
// loop of objects top side of rectangle
for (var i = this.minX; i <= this.maxX; i += this.patternDensity) {
rect(i, this.minY, this.margin * 2);
}
// loop of objects right side of rectangle
for (var i = this.minY; i <= this.maxY; i += this.patternDensity) {
rect(this.maxX, i, this.margin * 2);
}
// loop of objects bottom side of rectangle
for (var i = this.maxX; i >= this.minX; i -= this.patternDensity) {
rect(i, this.maxY, this.margin * 2);
}
// loop of objects left side of rectangle
for (var i = this.maxY; i >= this.minY; i -= this.patternDensity) {
rect(this.minX, i, this.margin * 2);
}
//this rect covers the uncompleted last rectangle of the left side loop of objects
rect(this.minX, this.minY, this.margin * 2);
fill(0);
beginShape();
vertex(this.minX + this.margin, this.minY + this.margin);
vertex(this.maxX - this.margin, this.minY + this.margin);
vertex(this.maxX - this.margin, this.maxY - this.margin);
vertex(this.minX + this.margin, this.maxY - this.margin);
endShape(CLOSE);
pop();
}
}
class Block {
constructor(globalSpeed) {
this.movingRect = new MovingShape();
this.movingShape = new MovingShape(globalSpeed);
}
update() {
this.movingRect.initShape();
this.movingRect.drawPattern();
//this.movingRect.displayInside();
//this.movingShape.moveInside();
this.movingShape.initShape();
this.movingShape.displayShape();
this.movingShape.moveShape();
}
}
let blocks = [];
let currentBlock;
function setup() {
createCanvas(600, 600);
newBlock();
}
function draw() {
background(100);
for (let i = 0; i < blocks.length; i++) {
blocks[i].update();
}
}
function newBlock() {
currentBlock = new Block(3);
blocks.push(currentBlock);
}
function mousePressed() {
currentBlock.movingRect.shapePressed();
currentBlock.movingShape.shapePressed();
}
function mouseReleased() {
currentBlock.movingRect.shapeReleased();
currentBlock.movingShape.shapeReleased();
newBlock();
}
Flexible Motion Grid: Instances
Below are three diferente instances of Flexible Motion Grid, each with different parametric values and inputs.