The concept of Sankofa, derived from the Akan people of Ghana, embodies the idea that one should remember the past to foster positive progress in the future. The Akan tribe, part of the larger Ashanti (or Asante) group, encapsulates a rich cultural heritage that emphasizes the importance of history and self-identity. The word “Sankofa” translates to “to retrieve,” embodying the proverb, “Se wo were fi na wosankofa a yenkyi,” meaning “it is not taboo to go back and get what you forgot.” This principle highlights that understanding our history is crucial for personal growth and cultural awareness.
This philosophy has greatly inspired my project. Adinkra symbols, with their deep historical roots and intricate patterns, serve as a central element of my work. These symbols carry meanings that far surpass my personal experiences, urging me to look back at my heritage. I aim to recreate these age-old symbols in a modern, interactive format that pays homage to their origins. It’s my way of going back into the past to get what is good and moving forward with it.
Embedded Sketch
Images
Coding Translation and Logic
The core of my sketch is a dynamic grid-based visualization that reflects Adinkra symbols, infused with movement and interaction through music. Here’s how I approached this creative endeavor:
Creating a Grid Layout
I divided the canvas into a grid structure, with each cell serving as a small canvas for a unique Adinkra symbol. I utilized a 2D array to manage the placement of these symbols efficiently.
I defined variables for columns and rows to control the grid structure.
I calculated cellSize for evenly spaced symbols.
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
let x = currentCol * cellSize;
let y = currentRow * cellSize;
let x = currentCol * cellSize;
let y = currentRow * cellSize;
let x = currentCol * cellSize;
let y = currentRow * cellSize;
Pattern Assignment
I created an array of Adinkra patterns, randomly assigning them to each grid cell for a vibrant, ever-evolving display.
I looped through the grid and calling drawPattern() to render each symbol.
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
functioninitializePatterns(){
patterns = [
drawThickVerticalLines,
drawNestedTriangles,
drawSymbols,
drawZebraPrint,
drawDiamondsInDiamond,
drawCurves,
drawThickHorizontalLines,
drawSquareSpiral,
drawSpiralTriangles,
thinLines,
verticalLines,
drawXWithDots,
];
}
let colorfulPalette = [
"#fcf3cf", // Light cream
"#DAF7A6", // Light green
"#FFC300", // Bright yellow
"#FF5733", // Bright red
"#C70039", // Dark red
"#900C3F", // Dark magenta
];
functioninitializeColors(){
colors = [
color(255, 132, 0), // Vibrant Orange
color(230, 115, 0), // Darker Orange
color(191, 87, 0), // Earthy Brownish Orange
color(140, 70, 20), // Dark Brown
color(87, 53, 19), // Rich Brown
color(255, 183, 77), // Light Golden Orange
];
}
functiondrawSpiralTriangles(x, y, size){
strokeWeight(2);
// Check the mode to set the stroke accordingly
if(currentMode === 0){
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
}elseif(currentMode === 1){
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
}elseif(currentMode === 2){
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
noFill();
// Adjust the initial size to ensure the triangle fits inside the cell
let adjustedSize = size * 0.9; // Reduce size slightly for padding
// Draw the recursive triangles centered in the cell
recursiveTriangle(
x - adjustedSize / 2,
y - adjustedSize / 2,
adjustedSize,
5
);
}
functionrecursiveTriangle(x, y, size, depth){
if(depth == 0)return;
// Draw the outer triangle
let half = size / 2;
triangle(x, y, x + size, y, x + half, y + size);
// Recursively draw smaller triangles inside
recursiveTriangle(x, y, size / 2, depth - 1); // Top-left
recursiveTriangle(x + half / 2, y + size /2, size / 2, depth - 1); // Center
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
}elseif(currentMode === 1){
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
}elseif(currentMode === 2){
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
noFill();
for(let i = 0; i < 5; i++){
beginShape();
vertex(0, -dSize / 2);
vertex(dSize / 2, 0);
vertex(0, dSize / 2);
vertex(-dSize / 2, 0);
endShape(CLOSE);
dSize *= 0.7;
}
}
// Bezier Curves
functiondrawCurves(x, y, size){
noFill();
if(currentMode === 0){
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
}elseif(currentMode === 1){
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
}elseif(currentMode === 2){
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
strokeWeight(3);
for(let i = 0; i < 6; i++){
bezier(
-size / 2,
-size / 2,
random(-size, size),
random(-size, size),
random(-size, size),
random(-size, size),
size / 2,
size / 2
);
}
}
function initializePatterns() {
patterns = [
drawThickVerticalLines,
drawNestedTriangles,
drawSymbols,
drawZebraPrint,
drawDiamondsInDiamond,
drawCurves,
drawThickHorizontalLines,
drawSquareSpiral,
drawSpiralTriangles,
thinLines,
verticalLines,
drawXWithDots,
];
}
let colorfulPalette = [
"#fcf3cf", // Light cream
"#DAF7A6", // Light green
"#FFC300", // Bright yellow
"#FF5733", // Bright red
"#C70039", // Dark red
"#900C3F", // Dark magenta
];
function initializeColors() {
colors = [
color(255, 132, 0), // Vibrant Orange
color(230, 115, 0), // Darker Orange
color(191, 87, 0), // Earthy Brownish Orange
color(140, 70, 20), // Dark Brown
color(87, 53, 19), // Rich Brown
color(255, 183, 77), // Light Golden Orange
];
}
function drawSpiralTriangles(x, y, size) {
strokeWeight(2);
// Check the mode to set the stroke accordingly
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
noFill();
// Adjust the initial size to ensure the triangle fits inside the cell
let adjustedSize = size * 0.9; // Reduce size slightly for padding
// Draw the recursive triangles centered in the cell
recursiveTriangle(
x - adjustedSize / 2,
y - adjustedSize / 2,
adjustedSize,
5
);
}
function recursiveTriangle(x, y, size, depth) {
if (depth == 0) return;
// Draw the outer triangle
let half = size / 2;
triangle(x, y, x + size, y, x + half, y + size);
// Recursively draw smaller triangles inside
recursiveTriangle(x, y, size / 2, depth - 1); // Top-left
recursiveTriangle(x + half / 2, y + size / 2, size / 2, depth - 1); // Center
recursiveTriangle(x + half, y, size / 2, depth - 1); // Top-right
}
function drawZigZagPattern(x, y, size) {
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
noFill();
let amplitude = size / 4;
let frequency = size / 5;
// Draw zigzag shape and add dots
beginShape();
for (let i = 0; i <= size; i += frequency) {
let yOffset = (i / frequency) % 2 == 0 ? -amplitude : amplitude; // Create zigzag pattern
let currentX = x - size / 2 + i; // Current X position
let currentY = y + yOffset; // Current Y position
vertex(currentX, currentY);
// Calculate the vertices of the triangle
if (i > 0) {
// The triangle's vertices are:
// Previous vertex
let previousY = y + ((i / frequency) % 2 == 0 ? amplitude : -amplitude);
let triangleVertices = [
createVector(currentX, currentY), // Current peak
createVector(currentX - frequency / 2, previousY), // Left point
createVector(currentX + frequency / 2, previousY), // Right point
];
// Calculate the centroid of the triangle
let centroidX =
(triangleVertices[0].x +
triangleVertices[1].x +
triangleVertices[2].x) /
3;
let centroidY =
(triangleVertices[0].y +
triangleVertices[1].y +
triangleVertices[2].y) /
3;
// Draw a dot at the centroid
strokeWeight(5); // Set stroke weight for dots
point(centroidX, centroidY); // Draw the dot
}
}
endShape();
}
function drawXWithDots(x, y, size) {
noFill();
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
// Draw the two diagonal lines to form the "X"
line(x - size / 2, y - size / 2, x + size / 2, y + size / 2); // Line from top-left to bottom-right
line(x - size / 2, y + size / 2, x + size / 2, y - size / 2); // Line from bottom-left to top-right
// Set fill for the dots
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
let dotSize = 10; // Size of the dots
// Calculate positions for the dots in each triangle formed by the "X"
// Top-left triangle
ellipse(x - size / 4, y - size / 4, dotSize, dotSize);
// Top-right triangle
ellipse(x + size / 4, y - size / 4, dotSize, dotSize);
// Bottom-left triangle
ellipse(x - size / 4, y + size / 4, dotSize, dotSize);
// Bottom-right triangle
ellipse(x + size / 4, y + size / 4, dotSize, dotSize);
}
//thin lines
function verticalLines(x, y, size) {
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
strokeWeight(2);
let gap = size / 5;
for (let i = 0; i < 6; i++) {
line(-size / 2 + gap * i, -size / 2, -size / 2 + gap * i, size / 2);
}
}
// Thick Vertical Lines
function drawThickVerticalLines(x, y, size) {
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
strokeWeight(10); // Thick line weight
let gap = size / 5; // 5 lines with gaps
for (let i = 0; i < 6; i++) {
line(-size / 2 + gap * i, -size / 2, -size / 2 + gap * i, size / 2);
}
}
// Thick Horizontal Lines
function drawThickHorizontalLines(x, y, size) {
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
strokeWeight(10); // Thick line weight
let gap = size / 6; // 5 lines with gaps
for (let i = 0; i < 6; i++) {
line(
-size / 2,
-size / 2 + gap * (i + 1),
size / 2,
-size / 2 + gap * (i + 1)
);
}
}
// Thin Horizontal Lines
function thinLines(x, y, size) {
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
strokeWeight(2); // Thick line weight
let gap = size / 6; // 5 lines with gaps
for (let i = 0; i < 6; i++) {
line(
-size / 2,
-size / 2 + gap * (i + 1),
size / 2,
-size / 2 + gap * (i + 1)
);
}
}
// Nested Triangles
function drawNestedTriangles(x, y, size) {
let triangleSize = size;
noFill();
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
strokeWeight(2);
for (let i = 0; i < 4; i++) {
triangle(
-triangleSize / 2,
triangleSize / 2,
triangleSize / 2,
triangleSize / 2,
0,
-triangleSize / 2
);
triangleSize *= 0.7;
}
}
// West African Symbols/Geometric Shapes
function drawSymbols(x, y, size) {
noFill();
let symbolSize = size * 0.6;
strokeWeight(2);
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
// Circle with horizontal/vertical line cross
ellipse(0, 0, symbolSize, symbolSize);
line(-symbolSize / 2, 0, symbolSize / 2, 0);
line(0, -symbolSize / 2, 0, symbolSize / 2);
// Small triangles within
for (let i = 0; i < 3; i++) {
let triSize = symbolSize * (0.3 - i * 0.1);
triangle(
0,
-triSize / 2,
triSize / 2,
triSize / 2,
-triSize / 2,
triSize / 2
);
}
}
// Zebra Print
function drawZebraPrint(x, y, size) {
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
strokeWeight(2);
let stripes = 10;
for (let i = 0; i < stripes; i++) {
let step = i * (size / stripes);
line(-size / 2 + step, -size / 2, size / 2 - step, size / 2);
line(size / 2 - step, -size / 2, -size / 2 + step, size / 2);
}
}
function drawSquareSpiral(x, y, size) {
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
strokeWeight(4); // Set the stroke weight for the spiral
noFill(); // No fill for the square spiral
let step = size / 10; // Define the step size for each movement inward
let currentSize = size; // Start with the full square size
let startX = -currentSize / 2; // Initial X position (top-left corner)
let startY = -currentSize / 2; // Initial Y position (top-left corner)
beginShape(); // Start drawing the shape
// Draw the spiral by progressively making the square smaller and moving inward
while (currentSize > step) {
// Top edge
vertex(startX, startY);
vertex(startX + currentSize, startY);
// Right edge
vertex(startX + currentSize, startY + currentSize);
// Bottom edge
vertex(startX, startY + currentSize);
// Move inward for the next iteration
currentSize -= step * 2;
startX += step;
startY += step;
}
endShape();
}
// Diamonds within Diamonds
function drawDiamondsInDiamond(x, y, size) {
let dSize = size;
strokeWeight(2);
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
noFill();
for (let i = 0; i < 5; i++) {
beginShape();
vertex(0, -dSize / 2);
vertex(dSize / 2, 0);
vertex(0, dSize / 2);
vertex(-dSize / 2, 0);
endShape(CLOSE);
dSize *= 0.7;
}
}
// Bezier Curves
function drawCurves(x, y, size) {
noFill();
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
strokeWeight(3);
for (let i = 0; i < 6; i++) {
bezier(
-size / 2,
-size / 2,
random(-size, size),
random(-size, size),
random(-size, size),
random(-size, size),
size / 2,
size / 2
);
}
}
function initializePatterns() {
patterns = [
drawThickVerticalLines,
drawNestedTriangles,
drawSymbols,
drawZebraPrint,
drawDiamondsInDiamond,
drawCurves,
drawThickHorizontalLines,
drawSquareSpiral,
drawSpiralTriangles,
thinLines,
verticalLines,
drawXWithDots,
];
}
let colorfulPalette = [
"#fcf3cf", // Light cream
"#DAF7A6", // Light green
"#FFC300", // Bright yellow
"#FF5733", // Bright red
"#C70039", // Dark red
"#900C3F", // Dark magenta
];
function initializeColors() {
colors = [
color(255, 132, 0), // Vibrant Orange
color(230, 115, 0), // Darker Orange
color(191, 87, 0), // Earthy Brownish Orange
color(140, 70, 20), // Dark Brown
color(87, 53, 19), // Rich Brown
color(255, 183, 77), // Light Golden Orange
];
}
function drawSpiralTriangles(x, y, size) {
strokeWeight(2);
// Check the mode to set the stroke accordingly
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
noFill();
// Adjust the initial size to ensure the triangle fits inside the cell
let adjustedSize = size * 0.9; // Reduce size slightly for padding
// Draw the recursive triangles centered in the cell
recursiveTriangle(
x - adjustedSize / 2,
y - adjustedSize / 2,
adjustedSize,
5
);
}
function recursiveTriangle(x, y, size, depth) {
if (depth == 0) return;
// Draw the outer triangle
let half = size / 2;
triangle(x, y, x + size, y, x + half, y + size);
// Recursively draw smaller triangles inside
recursiveTriangle(x, y, size / 2, depth - 1); // Top-left
recursiveTriangle(x + half / 2, y + size / 2, size / 2, depth - 1); // Center
recursiveTriangle(x + half, y, size / 2, depth - 1); // Top-right
}
function drawZigZagPattern(x, y, size) {
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
noFill();
let amplitude = size / 4;
let frequency = size / 5;
// Draw zigzag shape and add dots
beginShape();
for (let i = 0; i <= size; i += frequency) {
let yOffset = (i / frequency) % 2 == 0 ? -amplitude : amplitude; // Create zigzag pattern
let currentX = x - size / 2 + i; // Current X position
let currentY = y + yOffset; // Current Y position
vertex(currentX, currentY);
// Calculate the vertices of the triangle
if (i > 0) {
// The triangle's vertices are:
// Previous vertex
let previousY = y + ((i / frequency) % 2 == 0 ? amplitude : -amplitude);
let triangleVertices = [
createVector(currentX, currentY), // Current peak
createVector(currentX - frequency / 2, previousY), // Left point
createVector(currentX + frequency / 2, previousY), // Right point
];
// Calculate the centroid of the triangle
let centroidX =
(triangleVertices[0].x +
triangleVertices[1].x +
triangleVertices[2].x) /
3;
let centroidY =
(triangleVertices[0].y +
triangleVertices[1].y +
triangleVertices[2].y) /
3;
// Draw a dot at the centroid
strokeWeight(5); // Set stroke weight for dots
point(centroidX, centroidY); // Draw the dot
}
}
endShape();
}
function drawXWithDots(x, y, size) {
noFill();
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
// Draw the two diagonal lines to form the "X"
line(x - size / 2, y - size / 2, x + size / 2, y + size / 2); // Line from top-left to bottom-right
line(x - size / 2, y + size / 2, x + size / 2, y - size / 2); // Line from bottom-left to top-right
// Set fill for the dots
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
let dotSize = 10; // Size of the dots
// Calculate positions for the dots in each triangle formed by the "X"
// Top-left triangle
ellipse(x - size / 4, y - size / 4, dotSize, dotSize);
// Top-right triangle
ellipse(x + size / 4, y - size / 4, dotSize, dotSize);
// Bottom-left triangle
ellipse(x - size / 4, y + size / 4, dotSize, dotSize);
// Bottom-right triangle
ellipse(x + size / 4, y + size / 4, dotSize, dotSize);
}
//thin lines
function verticalLines(x, y, size) {
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
strokeWeight(2);
let gap = size / 5;
for (let i = 0; i < 6; i++) {
line(-size / 2 + gap * i, -size / 2, -size / 2 + gap * i, size / 2);
}
}
// Thick Vertical Lines
function drawThickVerticalLines(x, y, size) {
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
strokeWeight(10); // Thick line weight
let gap = size / 5; // 5 lines with gaps
for (let i = 0; i < 6; i++) {
line(-size / 2 + gap * i, -size / 2, -size / 2 + gap * i, size / 2);
}
}
// Thick Horizontal Lines
function drawThickHorizontalLines(x, y, size) {
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
strokeWeight(10); // Thick line weight
let gap = size / 6; // 5 lines with gaps
for (let i = 0; i < 6; i++) {
line(
-size / 2,
-size / 2 + gap * (i + 1),
size / 2,
-size / 2 + gap * (i + 1)
);
}
}
// Thin Horizontal Lines
function thinLines(x, y, size) {
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
strokeWeight(2); // Thick line weight
let gap = size / 6; // 5 lines with gaps
for (let i = 0; i < 6; i++) {
line(
-size / 2,
-size / 2 + gap * (i + 1),
size / 2,
-size / 2 + gap * (i + 1)
);
}
}
// Nested Triangles
function drawNestedTriangles(x, y, size) {
let triangleSize = size;
noFill();
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
strokeWeight(2);
for (let i = 0; i < 4; i++) {
triangle(
-triangleSize / 2,
triangleSize / 2,
triangleSize / 2,
triangleSize / 2,
0,
-triangleSize / 2
);
triangleSize *= 0.7;
}
}
// West African Symbols/Geometric Shapes
function drawSymbols(x, y, size) {
noFill();
let symbolSize = size * 0.6;
strokeWeight(2);
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
// Circle with horizontal/vertical line cross
ellipse(0, 0, symbolSize, symbolSize);
line(-symbolSize / 2, 0, symbolSize / 2, 0);
line(0, -symbolSize / 2, 0, symbolSize / 2);
// Small triangles within
for (let i = 0; i < 3; i++) {
let triSize = symbolSize * (0.3 - i * 0.1);
triangle(
0,
-triSize / 2,
triSize / 2,
triSize / 2,
-triSize / 2,
triSize / 2
);
}
}
// Zebra Print
function drawZebraPrint(x, y, size) {
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
strokeWeight(2);
let stripes = 10;
for (let i = 0; i < stripes; i++) {
let step = i * (size / stripes);
line(-size / 2 + step, -size / 2, size / 2 - step, size / 2);
line(size / 2 - step, -size / 2, -size / 2 + step, size / 2);
}
}
function drawSquareSpiral(x, y, size) {
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
strokeWeight(4); // Set the stroke weight for the spiral
noFill(); // No fill for the square spiral
let step = size / 10; // Define the step size for each movement inward
let currentSize = size; // Start with the full square size
let startX = -currentSize / 2; // Initial X position (top-left corner)
let startY = -currentSize / 2; // Initial Y position (top-left corner)
beginShape(); // Start drawing the shape
// Draw the spiral by progressively making the square smaller and moving inward
while (currentSize > step) {
// Top edge
vertex(startX, startY);
vertex(startX + currentSize, startY);
// Right edge
vertex(startX + currentSize, startY + currentSize);
// Bottom edge
vertex(startX, startY + currentSize);
// Move inward for the next iteration
currentSize -= step * 2;
startX += step;
startY += step;
}
endShape();
}
// Diamonds within Diamonds
function drawDiamondsInDiamond(x, y, size) {
let dSize = size;
strokeWeight(2);
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
noFill();
for (let i = 0; i < 5; i++) {
beginShape();
vertex(0, -dSize / 2);
vertex(dSize / 2, 0);
vertex(0, dSize / 2);
vertex(-dSize / 2, 0);
endShape(CLOSE);
dSize *= 0.7;
}
}
// Bezier Curves
function drawCurves(x, y, size) {
noFill();
if (currentMode === 0) {
// Regular mode: Use random colors from the regular palette
stroke(random(colors));
} else if (currentMode === 1) {
// Colorful mode: Use colors from the colorfulPalette
stroke(random(colorfulPalette));
} else if (currentMode === 2) {
// Random Size Mode: Use random colors from the regular palette
stroke(random(colors));
}
strokeWeight(3);
for (let i = 0; i < 6; i++) {
bezier(
-size / 2,
-size / 2,
random(-size, size),
random(-size, size),
random(-size, size),
random(-size, size),
size / 2,
size / 2
);
}
}
Introducing Modes
To enhance user engagement, I implemented multiple visual modes (Regular, Colorful, Randomized, and Monochrome), allowing diverse experiences based on user interaction.
I utilized a currentMode variable to switch between visual styles seamlessly.
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
functiondraw(){
// Set up the background for the current mode if needed
functiondrawPattern(x, y, patternIndex, size = cellSize){
if(patterns[patternIndex]){
push();
translate(x + size / 2, y + size /2); // Center the pattern
patterns[patternIndex](0, 0, size); // Draw the pattern using the provided size
pop();
}
}
// Draw patterns in colorful mode using only colors from colorfulPalette
functiondrawColorfulPattern(x, y, patternIndex){
let chosenColor = random(colorfulPalette); // Choose a color from colorfulPalette
stroke(chosenColor); // Set stroke color
fill(chosenColor); // Set fill color for the colorful patterns
drawPattern(x, y, patternIndex); // Call the default drawPattern to handle the drawing
}
functiondrawAlternatingPatterns(x, y, col){
let patternIndex = col % patterns.length; // Alternate patterns based on column
drawPattern(x, y, patternIndex);
}
function draw() {
// Set up the background for the current mode if needed
if (frameCount === 1 || (currentCol === 0 && currentRow === 0)) {
setupBackground(); // Set up the background for the current mode
}
// Analyze the frequency spectrum
spectrum = fft.analyze();
// Average the bass frequencies for a stronger response
let bass = (spectrum[0] + spectrum[1] + spectrum[2]) / 3;
// Log bass to check its values
console.log(bass);
// Map bass amplitude for size variation and oscillation
let sizeVariation = map(bass, 0, 255, 0.8, 1.2);
let amplitude = map(bass, 0, 255, 0, 1); // Normalize to [0, 1]
// Use sine wave for oscillation based on time
let time = millis() * 0.005; // Control the speed of oscillation
let oscillation = sin(time * TWO_PI) * amplitude * 50; // Scale the oscillation
// Calculate position in the grid
let x = currentCol * cellSize;
let y = currentRow * cellSize;
// Apply the logic depending on currentMode
if (currentMode === 0) {
// Regular mode
if (currentRow % 3 === 0) {
drawZigZagPattern(
x + cellSize / 2,
y + cellSize / 2 + oscillation,
cellSize
); // Draw zigzag on 3rd row with oscillation
} else {
let patternIndex = (currentCol + currentRow * cols) % patterns.length;
drawPattern(x, y + oscillation, patternIndex); // Default pattern with oscillation
}
} else if (currentMode === 1) {
// Colorful mode - only use colors from colorfulPalette
let patternIndex = (currentCol + currentRow * cols) % patterns.length;
drawColorfulPattern(x, y + oscillation, patternIndex); // Apply oscillation
} else if (currentMode === 2) {
// Random Size mode
let patternIndex = (currentCol + currentRow * cols) % patterns.length;
let randomSize = random(0.5, 1.5) * cellSize; // Random size
drawPattern(x, y + oscillation, patternIndex, randomSize); // Apply oscillation
} else if (currentMode === 3) {
// Alternating Patterns
drawAlternatingPatterns(x, y + oscillation, currentCol); // Apply oscillation
}
// Move to the next cell
currentCol++;
if (currentCol >= cols) {
currentCol = 0;
currentRow++;
}
if (currentRow >= rows) {
noLoop(); // Stop the loop when all rows are drawn
}
}
function setupBackground() {
let colorModeChoice = int(random(3)); // Randomize the choice for background color
if (currentMode === 0 || currentMode === 1 || currentMode === 2) {
// Regular, Colorful, and Random Size Modes
if (colorModeChoice === 0) {
background(255); // White background
stroke(0); // Black stroke
} else if (colorModeChoice === 1) {
background(0); // Black background
stroke(255); // White stroke
} else {
background(50, 25, 0); // Dark brown background
stroke(255, 165, 0); // Orange lines
}
} else if (currentMode === 3) {
// Alternating Patterns Mode
if (colorModeChoice === 0) {
background(255); // White background
stroke(0); // Black stroke
} else if (colorModeChoice === 1) {
background(0); // Black background
stroke(255); // White stroke
}
// No stroke if colorModeChoice is 2 (do nothing)
}
}
// Regular draw pattern function
function drawPattern(x, y, patternIndex, size = cellSize) {
if (patterns[patternIndex]) {
push();
translate(x + size / 2, y + size / 2); // Center the pattern
patterns[patternIndex](0, 0, size); // Draw the pattern using the provided size
pop();
}
}
// Draw patterns in colorful mode using only colors from colorfulPalette
function drawColorfulPattern(x, y, patternIndex) {
let chosenColor = random(colorfulPalette); // Choose a color from colorfulPalette
stroke(chosenColor); // Set stroke color
fill(chosenColor); // Set fill color for the colorful patterns
drawPattern(x, y, patternIndex); // Call the default drawPattern to handle the drawing
}
function drawAlternatingPatterns(x, y, col) {
let patternIndex = col % patterns.length; // Alternate patterns based on column
drawPattern(x, y, patternIndex);
}
function draw() {
// Set up the background for the current mode if needed
if (frameCount === 1 || (currentCol === 0 && currentRow === 0)) {
setupBackground(); // Set up the background for the current mode
}
// Analyze the frequency spectrum
spectrum = fft.analyze();
// Average the bass frequencies for a stronger response
let bass = (spectrum[0] + spectrum[1] + spectrum[2]) / 3;
// Log bass to check its values
console.log(bass);
// Map bass amplitude for size variation and oscillation
let sizeVariation = map(bass, 0, 255, 0.8, 1.2);
let amplitude = map(bass, 0, 255, 0, 1); // Normalize to [0, 1]
// Use sine wave for oscillation based on time
let time = millis() * 0.005; // Control the speed of oscillation
let oscillation = sin(time * TWO_PI) * amplitude * 50; // Scale the oscillation
// Calculate position in the grid
let x = currentCol * cellSize;
let y = currentRow * cellSize;
// Apply the logic depending on currentMode
if (currentMode === 0) {
// Regular mode
if (currentRow % 3 === 0) {
drawZigZagPattern(
x + cellSize / 2,
y + cellSize / 2 + oscillation,
cellSize
); // Draw zigzag on 3rd row with oscillation
} else {
let patternIndex = (currentCol + currentRow * cols) % patterns.length;
drawPattern(x, y + oscillation, patternIndex); // Default pattern with oscillation
}
} else if (currentMode === 1) {
// Colorful mode - only use colors from colorfulPalette
let patternIndex = (currentCol + currentRow * cols) % patterns.length;
drawColorfulPattern(x, y + oscillation, patternIndex); // Apply oscillation
} else if (currentMode === 2) {
// Random Size mode
let patternIndex = (currentCol + currentRow * cols) % patterns.length;
let randomSize = random(0.5, 1.5) * cellSize; // Random size
drawPattern(x, y + oscillation, patternIndex, randomSize); // Apply oscillation
} else if (currentMode === 3) {
// Alternating Patterns
drawAlternatingPatterns(x, y + oscillation, currentCol); // Apply oscillation
}
// Move to the next cell
currentCol++;
if (currentCol >= cols) {
currentCol = 0;
currentRow++;
}
if (currentRow >= rows) {
noLoop(); // Stop the loop when all rows are drawn
}
}
function setupBackground() {
let colorModeChoice = int(random(3)); // Randomize the choice for background color
if (currentMode === 0 || currentMode === 1 || currentMode === 2) {
// Regular, Colorful, and Random Size Modes
if (colorModeChoice === 0) {
background(255); // White background
stroke(0); // Black stroke
} else if (colorModeChoice === 1) {
background(0); // Black background
stroke(255); // White stroke
} else {
background(50, 25, 0); // Dark brown background
stroke(255, 165, 0); // Orange lines
}
} else if (currentMode === 3) {
// Alternating Patterns Mode
if (colorModeChoice === 0) {
background(255); // White background
stroke(0); // Black stroke
} else if (colorModeChoice === 1) {
background(0); // Black background
stroke(255); // White stroke
}
// No stroke if colorModeChoice is 2 (do nothing)
}
}
// Regular draw pattern function
function drawPattern(x, y, patternIndex, size = cellSize) {
if (patterns[patternIndex]) {
push();
translate(x + size / 2, y + size / 2); // Center the pattern
patterns[patternIndex](0, 0, size); // Draw the pattern using the provided size
pop();
}
}
// Draw patterns in colorful mode using only colors from colorfulPalette
function drawColorfulPattern(x, y, patternIndex) {
let chosenColor = random(colorfulPalette); // Choose a color from colorfulPalette
stroke(chosenColor); // Set stroke color
fill(chosenColor); // Set fill color for the colorful patterns
drawPattern(x, y, patternIndex); // Call the default drawPattern to handle the drawing
}
function drawAlternatingPatterns(x, y, col) {
let patternIndex = col % patterns.length; // Alternate patterns based on column
drawPattern(x, y, patternIndex);
}
Colorful mode with Music:
Music Integration
I integrated p5.js’s sound library to create an interactive experience where patterns respond to music. The FFT (Fast Fourier Transform) analyzes audio amplitude, allowing the symbols to offset based on the music. Essentially, once the music starts playing the symbols either go up, or down randomly based on the music, and this alters the pattern drawn. So for each mode, there are two states, one where the music is playing and one where it is not.
I mapped bass frequencies to create lively, jittering movements.
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
let bass = (spectrum[0] + spectrum[1] + spectrum[2]) / 3;
let xOffset = random(-sizeVariation * 10, sizeVariation * 10);
let yOffset = random(-sizeVariation * 10, sizeVariation * 10);
drawPattern(x + xOffset, y + yOffset, patternIndex);
let bass = (spectrum[0] + spectrum[1] + spectrum[2]) / 3;
let xOffset = random(-sizeVariation * 10, sizeVariation * 10);
let yOffset = random(-sizeVariation * 10, sizeVariation * 10);
drawPattern(x + xOffset, y + yOffset, patternIndex);
let bass = (spectrum[0] + spectrum[1] + spectrum[2]) / 3;
let xOffset = random(-sizeVariation * 10, sizeVariation * 10);
let yOffset = random(-sizeVariation * 10, sizeVariation * 10);
drawPattern(x + xOffset, y + yOffset, patternIndex);
Achievements and Challenges
Achievements:
One of the achievements I am most proud of in this project is the implementation of multiple visual modes. I designed four distinct modes (Regular, Colorful, Randomized, and Monochrome) that allow users to experience the artwork in different ways. Each mode enhances user engagement and provides a unique perspective on the Adinkra symbols, making the project versatile and appealing. The smooth transitions between modes, triggered by key presses, add to the project’s interactivity and keep the viewer engaged.
Challenges:
Despite these successes, the journey was not without its challenges. One significant challenge was achieving a balance between the dynamic interaction of patterns and the constraints of the grid layout. Initially, the grid felt too rigid, making it difficult for the symbols to exhibit the desired randomness in their movements. To overcome this, I experimented with various techniques, such as introducing random offsets and modifying the size of the patterns to create a sense of organic movement within the structured grid. This iterative process taught me the importance of flexibility in design, especially when blending creativity with structured coding.
Another challenge was ensuring that each visual mode felt distinct and engaging. I initially struggled with mode transitions that felt too similar or jarring. By meticulously adjusting the visual elements in each mode—such as color schemes, pattern sizes, and overall aesthetics—I was able to develop a clearer identity for each mode. This process not only enhanced the user experience but also reinforced my understanding of how design choices can significantly impact perception and engagement.
Pen Plotting Translation and Process
The pen plotting process was straightforward yet time-consuming. Due to the dense nature of my project, I had to hide many layers to emphasize the vibrant colors of the patterns. While I didn’t change any code for plotting, I organized each layer by color to ensure a smooth plotting process. Overall, it took around two hours to complete!
Areas for Improvement and Future Work
Looking ahead, I aim to explore how to enhance the music’s impact on pattern dynamics. The grid structure, while beneficial, may limit randomness in movement. I’m excited to experiment with breaking down these constraints for more fluid interactions. Additionally, I dream of translating these patterns into fabric designs—what a fun endeavor that would be!