xxxxxxxxxx
500
// Hi Rupert, this script.js is the main program
// I've organized the file so that at the top here
// you will find all the things that you can tweak safely in your code.
// # 1. Transition Times
/////////////////////////
// There is a display time and a pause time, both add up to give the total time of a full shape cycle.
// Having a display time of 55 and a pause time of 5 means that each shape will be displayed for 55
// seconds and then be off for 5 more giving us a total cycle of one minute.
let DISPLAY_TIME = 55;
let PAUSE_TIME = 5;
// # 2. Shape Physics
//////////////////////
// Each type of shape has its own speed and amplitude, the speed handles the speed at which each shape turns
// and the amplitude handles the width of the circle around which each shape turn.
// The shapes speed and amplitude are given in the following order :
// Backgrounds, Heads, Hairs, Mouths, Symbols
let SPEEDS = [ 1, 3, 5, 20, 4]
let AMPLITUDES = [ 100, 70, 50, 20, 10]
// # 3. Adding New Shapes
//////////////////////////
// To add a new shape you must :
// a. make an svg drawing
// b. go into the svg file and take out the content betweent the <style> and </style> tags
// example >> <style>.cls-1{fill:#d40000;stroke-width:0px;}</style>
// c. in the same file, specify the SVG id, adding the id attribute and one of the 5 values : BACKGROUND, HEAD, HAIR, MOUTH or NUMBERS_OR_LETTERS
// example >> <svg id="NUMBERS_OR_LETTERS" xmlns="http://www.w3.org/2000/svg"
// d. drop the new svg in the corresponding folder and make sure it is named sequentially
// e. change the value in the preload function below to fit the number of items within the folder to which you added
function preload() {
backgrounds = loadImages(`images/background/`, 19);
heads = loadImages(`images/head/`, 12);
hairs = loadImages(`images/hair/`, 22);
mouths = loadImages(`images/mouth/`, 18);
symbols = loadImages(`images/symbol/`, 20);
}
// # 4. Changing Colors
////////////////////////
// Here you will find the color palette attribution per shape type along with the usual color array that you had before.
// I deactivated the blacks because they came to often. Feel free to uncomment it
function selectColor(shapetype){
switch(shapetype){
case "head":
return colarray3; // assigning colarray3 to the heads type
case "mouth":
return colarray2; // assigning colarray2 to the mouth type
case "hair":
return colarray9; // assigning colarray9 to the hair type
case "symbol":
return colarray4; // assigning colarray4 to the symbol type
case "background":
return colarray5; // assigning colarray4 to the background type
default :
return colarray1;
}
}
let colarray1 = [ // monochrome
'#D4DFC7', // LightGreyGreen
'#353028', // VanDykeBrown
'#A49772', // Beige
'#696656', // Taupe
'#EBE1AA', // Cream
'#91998A', // Grey
'#D8B695', // Salmon
'#5C765F', // ChromeGreen
'#7F6E4B', // Bronze
'#405150', // GreyAqua
'#5B4632', // Brown
'#434D36', // HedgeGreen
'#6B706E' // Grey
];
let colarray2 = [ // drab/monochrome selection
// '#000000', // Black
'#696969', // DimGrey
'#A52A2A', // Brown
'#FAEBD7', // AntiqueWhite
'#D2B48C', // Tan
'#F0E68C', // Khaki
'#6B8E23', // OliveDrab
'#8FBC8F', // DarkSeaGreen
'#008080', // Teal
'#6495ED', // Cornflower
'#DB7093' // PaleVioletRed
];
let colarray3 = [ // compound selection
// '#000000', // Black
'#D09515', // Ochre
'#372D16', // DarkBrown
'#9D4500', // BrickRed
'#8EA9A5', // LightBlueGrey
'#15D080', // EmeraldGreen
'#FCF4BD' // OffWhite
];
let colarray4 = [ // warm selection
'#00895F', // AquaGreen
'#FFF0A5', // Buff
'#FFB03B', // Ochre
'#B64926', // WarmOrange
'#8E2800' // WarmDeepRed
];
let colarray5 = [ // Triadic selection etc
'#AF82B8', // Lilac
'#321138', // DeepPurple
'#6B5C34', // Bronze
'#22785C', // Emerald Green
'#E0C05F', // LightOchre
'#B88500', // RawSienna
'#688BA3', // LightGreyBlue
'#BCD9FF', // LightGrey
'#193447', // MidGreyBlue
'#422120', // Maroon
'#575733', // Khaki
'#D95554', // Salmon
'#FFD88E', // Cream
'#152E29', // DarkGreen
'#00002E' // Indigo
];
let colarray6 = [ // Warm red golds b/w blues
'#D5541D', //Vermillion
'#a62500', // WarmRed
'#AD4318', // IndianRed
'#873413', // DeepRed
'#D48E1E', // Gold
'#AD7418', // Ochre
'#875B13', // Sienna
'#2B2B2B', // Black
'#D4D4D4', // LightGrey
'#29496D', // MidBlue
'#467DB8', // LightMidBlue
'#3a4553', // DarkGreyBlue
'#59726f', // MidGreyBlue
'#6B6129' // Olive
];
let colarray7 = [
'#400000', // Burgundy (shades 1 - 3 Peach)
'#651c1a', // 1
'#87493c', // 2
'#d09176', // Peach
'#3a1f00', // DarkBrown
'#4e3b1d', // 1
'#685e42', // 2
'#7f7e63', // 3
'#9a9d87', // LightGreyBrown
'#00221f', // DarkGreen
'#26453d', // 1
'#4c685c', // 2
'#728b7a', // 3
'#b3c6ae', // LightGreen
'#1a2844', // DarkGreyBlue
'#324b60', // 1
'#4a6d7b', // 2
'#639097', // 3
'#8bcac5', // LightBlue
'#331d48', // Aubergine
'#5a4557', // 1
'#816380', // 2
'#a8859c', // 3
'#cfa8b8', // LightViolet
'#000000' // Black
];
let colarray8 = [
'#FFFF00', '#00D5D5', '#FF0B0B', '#00D56A', '#FF0B85',
'#0B0BFF', '#008080', '#08b7fb', '#08fbc4', '#5a000e', '#00436b',
// '#000000'
]// bright and v dark colours
let colarray9 = [
// '#000000', // Black
'#8C940B', // LightOlive
'#AAAD79', // LightBuff
'#022747', // DarkPetrolBlue
'#541E1C', // DeepRussett
'#135894' // WedgewoodBlue
];
let colarray10 = [ // X11 named colours
// '#000000', // Black
'#8B4513', // SaddleBrown
'#FFC0CB', // Pink
'#F08080', // LightCoral
'#CD5C5C', // IndianRed
'#DC143C', // Crimson
'#B22222', // FireBrick
'#7F0000', // WebMaroon
'#8B0000', // DarkRed
'#EEE8AA', // PaleGoldenrod
'#B8860B', // DarkGoldenrod
'#FFD700', // Gold
'#BDB76B', // DarkKhaki
'#808000', // Olive
'#556B2F', // DarkOliveGreen
'#006400', // DarkGreen
'#008080', // Teal
'#2F4F4F', // DarkSlateGrey
'#5F9EA0', // CadetBlue
'#000080', // NavyBlue
'#483D8B', // DarkSlateBlue
'#663399', // RebeccaPurple
'#4B0082', // Indigo
'#B03060' // Maroon
];
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Down here is my code
class Environment {
constructor(base, backgrounds, heads, hairs) {
this.bodyParts = [];
this.bodyParts.push(new Shape('background', backgrounds, 0, SPEEDS[0], AMPLITUDES[0]));
this.bodyParts.push(new Shape('head', heads, FT/4, SPEEDS[1], AMPLITUDES[1]));
this.bodyParts.push(new Shape('hair', hairs, FT/4*2, SPEEDS[2], AMPLITUDES[2]));
this.bodyParts.push(new Shape('mouth', mouths, FT/4*3, SPEEDS[3], AMPLITUDES[3]));
this.bodyParts.push(new Shape('symbol',symbols, FT, SPEEDS[4], AMPLITUDES[4]));
this.base = shuffle(base);
this.currentColorIndex = 0;
this.nextColorIndex = ( this.currentColorIndex + 1) % base.length;
this.startTime = millis();
this.transitionDuration = 5000; // 20 seconds in milliseconds
}
run(){
this.backgroundChange(this.base);
for(let i = 0 ; i < this.bodyParts.length ; i++){
this.bodyParts[i].update();
}
this.displayAll();
}
backgroundChange(base) {
let currentTime = millis();
let elapsedTime = currentTime - this.startTime;
if (elapsedTime > this.transitionDuration) {
elapsedTime = 0;
this.startTime = currentTime;
this.currentColorIndex = this.nextColorIndex;
this.nextColorIndex = (this.currentColorIndex + 1) % base.length;
}
let lerpAmount = map(elapsedTime, 0, this.transitionDuration, 0, 1);
let currentColor = lerpColor(color(this.base[this.currentColorIndex]), color(this.base[this.nextColorIndex]), lerpAmount);
background(currentColor);
}
displayAll(){
let shapies = querySVG('svg#BACKGROUND');
for(let i = 0; i < shapies.length ; i++){
shapies[i].attribute('fill', this.bodyParts[0].color);
}
shapies = querySVG('svg#HEAD');
for(let i = 0; i < shapies.length ; i++){
shapies[i].attribute('fill', this.bodyParts[1].color);
}
shapies = querySVG('svg#HAIR');
for(let i = 0; i < shapies.length ; i++){
shapies[i].attribute('fill', this.bodyParts[2].color);
}
shapies = querySVG('svg#MOUTH');
for(let i = 0; i < shapies.length ; i++){
shapies[i].attribute('fill', this.bodyParts[3].color);
}
shapies = querySVG('svg#NUMBERS_OR_LETTERS');
for(let i = 0; i < shapies.length ; i++){
shapies[i].attribute('fill', this.bodyParts[4].color);
}
}
}
class Shape {
constructor(type, shapes, timerOffset=0, speed=10, amplitude=10){
// Meta
this.type = type;
this.shapes = shapes;
// Drawing
this.svg = random(this.shapes);
this.show = true;
this.colorpalette = selectColor(this.type);
this.color = random(this.colorpalette)
// Physics
this.pos = createVector(width/2, height/2);
// this.vel = createVector(0,0);
// this.acc = createVector(0,0);
// this.speed = 1;
// this.maxSpeed = 1.5;
// this.minSpeed = 0.001;
// this.maxSteer = 10;
// this.wanderAngle = 0;
// Physics Two
this.speed = speed;
this.amplitude = amplitude;
this.xDirection = random([-1,1])
this.yDirection = random([-1,1])
// Transition Control
this.timer = timerOffset; // 0 or offset
}
update(){
//this.move()
this.movetwo()
this.display()
this.timer++;
if(this.timer > DT){ // if timer is superior to display time
this.show = false; // stop displaying
if(this.timer > ( DT + PT )){// if timer is superior do display time AND pause time
this.svg = this.getNewShape();
this.color = random(this.colorpalette); // get random color from the right color palette
this.pos = createVector(width/2, height/2)
this.show = true;
this.xDirection = random([-1,1])
this.yDirection = random([-1,1])
this.timer = 0;
}
}
}
getNewShape(){
let randomShape = random(this.shapes);
while(randomShape === this.svg){
randomShape = random(this.shapes);
}
return randomShape;
}
display(opacity) {
tint(255,0)
if(this.svg && this.show){
push();
let offsetX = width/2 - this.pos.x;
let offsetY = height/2 - this.pos.y;
image(this.svg, offsetX, offsetY, width,height);
pop();
}
}
movetwo(){
let speedDivisor = 200/this.speed;
this.pos.x = width/2 - (cos(frameCount/speedDivisor) * this.amplitude + 0.2) * this.xDirection
this.pos.y = height/2 - (sin(frameCount/speedDivisor) * this.amplitude ) * this.yDirection
}
move() {
this.wander();
// Update Velocity
this.vel.add(this.acc);
this.vel.limit(this.maxSpeed);
// Update Position
this.pos.add(this.vel);
this.acc = createVector(0, 0);
this.constrain();
}
applyForce(force, coef=1) { // apply force
force.limit(this.maxSteer);
force.mult(coef);
this.acc.add(force);
//this.p[i].acc.limit(this.maxSteer);
}
wander(coef=100) {
const circleDistance = 30; // distance between particle and circle
const angleStep = 1; // size of random angle step increment
//
let circlePosition;
if(this.vel.x != 0 && this.vel.y != 0){
circlePosition = this.vel.copy(); // copy velocity into circle
}
else{
circlePosition = p5.Vector.random2D();
}
circlePosition.normalize();
circlePosition.mult(circleDistance); // set the circle position ahead of the particle
// now we need to have an angle set, and increment it with some random every step
this.wanderAngle += random() * angleStep - angleStep * 0.5;
//
let displacement = createVector(0, -1); // initial direction
displacement.mult(circleDistance); // set direction magnitude
displacement.rotate(this.wanderAngle); // rotate direction according to the wander angle
const desired = p5.Vector.add(circlePosition, displacement);
const steering = p5.Vector.sub(desired, this.vel);
this.applyForce(steering, coef);
}
constrain(){
if(this.pos.x < 0){
this.pos.x = 0;
}
if(this.pos.x > width){
this.pos.x = width
}
if(this.pos.y < 0){
this.pos.y = 0;
}
if(this.pos.y > height){
this.pos.y = height;
}
}
}
let env;
let heads = [];
let hairs = [];
let mouths = [];
let backgrounds = [];
let symbols = [];
let base = colarray5;
let scaling;
let DT = DISPLAY_TIME * 60
let PT = PAUSE_TIME * 60
let FT = DT + PT // 10/4
function loadImages(path, maxCount) {
let images = [];
for (let i = 1; i < maxCount + 1; i++) {
loadSVG(path + i + '.svg', img => {
images.push(img);
}, () => {
console.error(`Failed to load image ${path}${i}.svg`);
});
}
return images;
}
function setup() {
let newHeight = windowHeight;
let aspectRatio = 2560 / 1600;
let newWidth = newHeight * aspectRatio;
scaling = 2560 / newWidth;
createCanvas(newWidth, newHeight, SVG);
env = new Environment(base, backgrounds, heads, hairs, mouths, symbols);
frameRate(60)
}
function draw(){
background(255)
push()
env.run()
pop()
}