Browse Source

add gpu smoke / corruption effect

main
James Fenn 1 month ago
parent
commit
1aec9f9c67
3 changed files with 102 additions and 12 deletions
  1. +16
    -0
      README.md
  2. BIN
      corrupted.png
  3. +86
    -12
      sketch.js

+ 16
- 0
README.md View File

@@ -0,0 +1,16 @@
## Prelude

For my introduction piece, I have created a website: https://jfenn.me/englit0512-introduction/

Worth noting, I designed this to be viewed on a laptop/desktop, not a mobile or touchscreen device, so it will work a lot better if you have access to one. Also, it uses some 3D transform/scaling features that might vary between browsers - so if you see things that are misaligned or look a bit off, it is not intentional. I will say that I've tested this pretty thoroughly on my laptop and a couple friends have done the same, but I still cannot guarantee it will work for everyone. Web development is hard.

## Design

I wrote this website using [p5js](https://p5js.org), a JavaScript graphics library that allows developers to easily create small interactive programs like this one. It also uses some music by [Punch Deck](https://punchdeck.bandcamp.com), under the [Creative Commons Attribution 3.0 Unported](https://creativecommons.org/licenses/by/3.0/) license.

As this is an introduction piece, I started by thinking about my identity and the information I wanted to include. I write software, I play games, I do weird things with technology and enjoy finding little bugs and "features" in its many forms. A good way to connect all this together - and very topical, as it is what I see the most of these days - is the view of my desk.

I initially wanted to design this "game" as a point-and-click adventure that might take the player between different rooms and scenes, but I quickly realized that I did not have enough content to fill more than one. I have added some dynamic features to this scene, however - the game playing on my laptop adds some motion and makes the scene feel "alive," and the flickering light on my GPU serves a similar purpose.

Hovering over each "object" on my desk shows an animated tooltip - using a simple `sin(frameCount / PI)` function to create the motion - that briefly explains the purpose of the object and prompts the user to click on it (or makes it obvious that it *can* be clicked on).


BIN
corrupted.png View File

Before After
Width: 1022  |  Height: 765  |  Size: 2.2 MiB

+ 86
- 12
sketch.js View File

@@ -16,6 +16,9 @@ let _message = {
visible: true
};

let _smokeLevel = 0;
let _smokeParticles = [];

let _mouseIsClicked = false;
let _mouseWasClicked = false;

@@ -35,6 +38,7 @@ function setup() {

function preload() {
_images.desk = loadImage('./scene-desk.jpg');
_images.corrupted = loadImage('./corrupted.png');
}

function draw() {
@@ -95,14 +99,6 @@ function draw() {
element.attribute("style", "display:none;");
});
}

if (!_sounds.music.paused) {
// music playing; draw credits
fill(50, 50, 50);
noStroke();
textSize(width/60);
text("Playing music by Punch Deck (Creative Commons)...", ...percent(5, 5, 90));
}
}

function draw_desk() {
@@ -116,6 +112,14 @@ function draw_desk() {
textSize(width/30);
text("James Fenn - he/him", ...percent(5, 10, 90));

if (!_sounds.music.paused) {
// music playing; draw credits
fill(50, 50, 50);
noStroke();
textSize(width/60);
text("Playing music by Punch Deck (Creative Commons)...", ...percent(5, 5, 90));
}

const canvasRect = canvas.getBoundingClientRect();
const twitchPosition = percent(6.8, 52, 25, 20.5);
_elementAttrs.twitchFrame.style = `
@@ -152,13 +156,27 @@ function draw_desk() {
create_arrow(...percent(33, 56, 15, 20), {
message: "My eGPU",
click: () => {
_message = {
text: "I've recently been setting up an external GPU for my laptop! The laptop runs Arch Linux - not Windows - and has a complicated window manager that makes things difficult. Sometimes when I run Zoom, the GPU decides it doesn't want to, and causes a kernel panic that locks out my entire PC!",
visible: true
};
if (_smokeLevel < 3) {
_smokeLevel++;
_message = {
text: "I've recently been setting up an external GPU for my laptop! The laptop runs Arch Linux - not Windows - and has a complicated window manager that makes things difficult. Sometimes when I run Zoom, the GPU decides it doesn't want to, and causes a kernel panic that locks out my entire PC!",
visible: true
};
} else {
_scene = 'error';
_message = {
text: "Look what you did! The GPU had too much smoke to render and it crashed! Now I gotta restart my laptop again...",
visible: true
};
}
}
});

create_smoke(...percent(38, 70));

if (frameCount % 3 == 0 && Math.random() < 0.2)
create_circleGradient(...percent(38.2, 75, 3), color(0, 0, 0, 150), color(0, 0, 0, 0));

// keyboard box
create_arrow(...percent(25, 85, 40, 15), {
message: "Mechanical keyboards are great!",
@@ -182,6 +200,11 @@ function draw_desk() {
});
}

function draw_error() {
image(_images.corrupted, ...percent(0, 0, 100, 100));
_elementAttrs.twitchFrame.style = "display: none;";
}

function create_arrow(x, y, w, h, { message, hover, click }) {
if (mouseInRect(...absolute(x, y, w, h)) && !_message.visible) {
// draw floating arrow
@@ -217,6 +240,57 @@ function create_arrow(x, y, w, h, { message, hover, click }) {
}
}

function create_circleGradient(x, y, r, c1, c2) {
noStroke();
r = Math.round(r);

for (let radius = r; radius > 0; --radius) {
fill(lerpColor(c1, c2, radius/r));
ellipse(x, y, radius, radius);
}
}

function create_smoke(x, y) {
if (frameCount % (10 - _smokeLevel) == 0) for (let i = 0; i < _smokeLevel; i++) {
_smokeParticles.push({
x, y,
ux: Math.random() - 0.5,
uy: 0,
dx: 0,
dy: -3,
r: 0,
dr: 1,
a: 0,
da: _smokeLevel,
ma: 180
});
}

noStroke();

if (frameCount % 50 == 0) { // it's like memory GC but specific to this particle system!
_smokeParticles = _smokeParticles.filter((particle) =>
particle.x + particle.r > 0 &&
particle.y + particle.r > 0 &&
particle.x - particle.r < width &&
particle.y - particle.r < height);
}

_smokeParticles.forEach((particle) => {
const r = (particle.r += particle.dr);
if (particle.x + r < 0 || particle.y + r < 0 || particle.x - r > width || particle.y - r > height)
return;

fill(100, 100, 100, particle.a = Math.min(particle.ma, particle.a + particle.da));

ellipse(
(particle.x += particle.dx) + (particle.ux * r),
(particle.y += particle.dy) + (particle.uy * r),
r, r
);
});
}

function windowResized() {
let scaledWidth = Math.min(windowHeight * (4/3), windowWidth) * 0.9;
let scaledHeight = Math.min(windowWidth * (3/4), windowHeight) * 0.9;


Loading…
Cancel
Save