xxxxxxxxxx
let video;
let captureReady = false;
let circlePressed = false;
let savedImage;
let retake;
let colorSelection;
let camera;
let touchImage; // New: image for touch effect
let touchEffectFrames = 0; // New: counter for the touch effect
// Define two separate arrays for saturated and neutral/muted colors
// Saturated Colors
const saturatedColors = [
// RED
{ name: 'Red (Dark)', value: [139, 0, 0] },
{ name: 'Red', value: [255, 0, 0] },
{ name: 'Red (Light)', value: [255, 102, 102] },
// ORANGE
{ name: 'Orange (Dark)', value: [255, 99, 71] },
{ name: 'Orange', value: [255, 165, 0] },
{ name: 'Orange (Light)', value: [255, 200, 102] },
// YELLOW
{ name: 'Yellow (Dark)', value: [204, 204, 0] },
{ name: 'Yellow', value: [255, 255, 0] },
{ name: 'Yellow (Light)', value: [255, 255, 153] },
// GREEN
{ name: 'Green (Dark)', value: [0, 100, 0] },
{ name: 'Green', value: [0, 255, 0] },
{ name: 'Green (Light)', value: [144, 238, 144] },
// BLUE
{ name: 'Blue (Dark)', value: [0, 0, 139] },
{ name: 'Blue', value: [0, 0, 255] },
{ name: 'Blue (Light)', value: [173, 216, 230] },
// PURPLE
{ name: 'Purple (Dark)', value: [75, 0, 130] },
{ name: 'Purple', value: [128, 0, 128] },
{ name: 'Purple (Light)', value: [221, 160, 221] },
];
const neutralColors = [
{ name: 'White', value: [255, 255, 255] },
{ name: 'Peach', value: [255, 218, 185] },
{ name: 'Almond', value: [230, 220, 150] },
{ name: 'Tan', value: [210, 176, 137] },
{ name: 'Gold', value: [212, 175, 55] },
{ name: 'Copper', value: [184, 115, 51] },
{ name: 'Caramel', value: [210, 105, 30] },
{ name: 'Grey', value: [127, 127, 127] },
{ name: 'Sienna', value: [160, 82, 45] },
{ name: 'Brown', value: [165, 42, 42] },
{ name: 'Mocha', value: [123, 63, 0] },
{ name: 'Light Tan', value: [100, 44, 35] },
{ name: 'Black', value: [0, 0, 0] },
];
const squareSize = 30; // Size of each color square
const horizontalSpacing = 5; // Horizontal spacing between the columns
// --- Custom Stroke Weight Slider Variables (for touch) ---
let swVal = 10; // Current stroke weight value
let swSliderX; // x-coordinate of slider (calculated in setup)
let swSliderY = 10; // y-coordinate of slider (top of canvas)
let swSliderW = 200; // slider width
let swSliderH = 20; // slider height
let adjustingSw = false; // flag to know if slider is being adjusted
function preload() {
retake = loadImage('camera_retake_icon_136829.png');
camera = loadImage('camera.png');
touchImage = loadImage('surface-touch-screen-icon.png'); // New: load the touch image
}
function setup() {
createCanvas(windowHeight, windowHeight);
// Create video capture
video = createCapture(VIDEO);
video.hide();
video.size(width, height);
video.elt.onloadeddata = function() {
captureReady = true;
};
retake.resize(width / 9, 0);
// Set slider X position at the top-right corner.
swSliderX = width - swSliderW;
}
function draw() {
// Display custom stroke weight slider at top right
drawSwSlider();
// New: if a mouse click triggered the effect, display a fullscreen background
// with the touch image for 20 frames.
if (touchEffectFrames > 0) {
background(255);
imageMode(CENTER);
image(touchImage, width / 2, height / 2);
touchEffectFrames--;
return; // Skip the rest of the drawing while the effect is active
}
if (!captureReady) {
fill(255);
textAlign(CENTER);
textSize(24);
text("Loading video...", width / 2, height / 2);
return;
}
if (!circlePressed) {
image(video, 0, 0, width, height);
}
// Draw colored squares for color selection when circle is pressed
if (circlePressed) {
noStroke();
// Left Column: Saturated Colors
for (let i = 0; i < saturatedColors.length; i++) {
let yPosition = 5 + i * (squareSize + 10);
fill(saturatedColors[i].value);
rect(10, yPosition, squareSize, squareSize);
}
// Right Column: Neutral/Muted Colors
for (let i = 0; i < neutralColors.length; i++) {
let yPosition = 5 + i * (squareSize + 10);
fill(neutralColors[i].value);
rect(10 + squareSize + horizontalSpacing, yPosition, squareSize, squareSize);
}
// Draw the retake button in the bottom-right corner
let fader = map(cos(frameCount / 10), -1, 1, 50, 150);
fill(200, 0, 0);
rect(width - retake.width, height - retake.height, retake.width, retake.height, 10);
tint(255, fader);
image(retake, width - retake.width, height - retake.height);
}
if (!circlePressed) {
// Draw the circle button for taking the snapshot
ellipseMode(CENTER);
fill(255, 255, 255);
noStroke();
ellipse(width / 2, height - 50, width / 8, height / 8);
imageMode(CENTER);
tint(255);
image(camera, width / 2, height - 50, width / 8, height / 8);
imageMode(CORNER);
}
// If a color has been selected, use it for drawing strokes on the saved image.
if (colorSelection) {
// Use swVal (custom slider) for stroke weight and the value of alphaSlider for transparency.
strokeWeight(swVal);
stroke(colorSelection[0], colorSelection[1], colorSelection[2]);
for (let i = 0; i < touches.length; i++) {
let touch = touches[i];
line(touch.x, touch.y, pmouseX, pmouseY);
}
}
}
// Draw our custom stroke weight slider on the canvas.
function drawSwSlider() {
// Draw slider track
fill(200);
noStroke();
rect(swSliderX, swSliderY, swSliderW, swSliderH, 5);
// Map current swVal (range 1-20) to a position along the slider
let handleX = map(swVal, 1, 20, swSliderX, swSliderX + swSliderW);
// Draw handle
fill(100);
ellipse(handleX, swSliderY + swSliderH / 2, 20, 20);
}
function touchStarted() {
// Only process if there is less than 2 touches.
if (touches.length >= 2) {
return false;
}
// Check if touch is inside the custom slider region
for (let t of touches) {
if (t.x >= swSliderX && t.x <= swSliderX + swSliderW &&
t.y >= swSliderY && t.y <= swSliderY + swSliderH) {
adjustingSw = true;
updateSwValue(t.x);
// Prevent further processing (like selecting a color) if adjusting the slider.
return false;
}
}
if (!circlePressed) {
// Check if the user tapped the circle button.
let d = dist(touches[0].x, touches[0].y, width / 2, height - 50);
if (d < width / 16) {
circlePressed = true;
savedImage = video.get();
if (savedImage) {
tint(255);
background(savedImage);
}
return false;
}
} else {
// Check for retake button tap.
if (touches[0].x > width - retake.width && touches[0].y > height - retake.height) {
circlePressed = false;
return false;
}
// Check left column for saturated color selection.
if (touches[0].x >= 10 && touches[0].x <= 10 + squareSize) {
for (let i = 0; i < saturatedColors.length; i++) {
let yPosition = 5 + i * (squareSize + 10);
if (touches[0].y >= yPosition && touches[0].y <= yPosition + squareSize) {
colorSelection = saturatedColors[i].value;
return false;
}
}
}
// Check right column for neutral/muted color selection.
let rightColumnX = 10 + squareSize + horizontalSpacing;
if (touches[0].x >= rightColumnX && touches[0].x <= rightColumnX + squareSize) {
for (let i = 0; i < neutralColors.length; i++) {
let yPosition = 5 + i * (squareSize + 10);
if (touches[0].y >= yPosition && touches[0].y <= yPosition + squareSize) {
colorSelection = neutralColors[i].value;
return false;
}
}
}
}
return false; // Prevent default behavior.
}
function touchMoved() {
// Only process if there is less than 2 touches.
if (touches.length >= 2) {
return false;
}
if (adjustingSw) {
// Update swVal from the first touch in the slider region.
updateSwValue(touches[0].x);
return false; // Consume this touch event.
}
if (colorSelection) {
strokeWeight(swVal);
stroke(colorSelection[0], colorSelection[1], colorSelection[2]);
for (let i = 0; i < touches.length; i++) {
let t = touches[i];
line(t.x, t.y, pmouseX, pmouseY);
}
}
return false;
}
function touchEnded() {
// Even if multiple touches are ended, we simply stop adjusting the slider.
adjustingSw = false;
return false; // Prevent default behavior.
}
// Helper: update the stroke weight value based on x coordinate within the slider track.
function updateSwValue(x) {
// Constrain x to slider bounds, then map to range 1–20.
let clampedX = constrain(x, swSliderX, swSliderX + swSliderW);
swVal = int(map(clampedX, swSliderX, swSliderX + swSliderW, 1, 50));
}
// New: if the user clicks with the mouse, trigger the fullscreen touch effect.
function mousePressed() {
touchEffectFrames = 20;
}