Skip to content

Instantly share code, notes, and snippets.

@harunpehlivan
Created May 30, 2021 13:38
Show Gist options
  • Save harunpehlivan/1c7d4ade65a2f06bb0389d5b9c0df508 to your computer and use it in GitHub Desktop.
Save harunpehlivan/1c7d4ade65a2f06bb0389d5b9c0df508 to your computer and use it in GitHub Desktop.
Mechanics of Sending Messages Backwards through Reborn Generations from the book "The First Fifteen Lives of Harry August"
<div><span><strong>Life</strong> Gen 1 → Gen 8</span></div>
<div><span><strong>Message</strong> Gen 1 ← Gen 8</span></div>
<div>
<canvas height="1200" width="1200"></canvas>
</div>

Mechanics of Sending Messages Backwards through Reborn Generations from the book "The First Fifteen Lives of Harry August"

A visualization of a message being passed backward through time as described in the book The First Fifteen Lives of Harry August.

In the story, some people are reborn and relive their lives over and over. In order to send a message backward in time to other people, a person at the beginning of their life relays a message to a person at the end of their life. When the older person is reborn, they do the same. This is a visualization of that process.

Each block represents a person's timeline. The moving line in their block represents their life's progress. The gray area is where a life overlaps another. When these are synced, a message could be passed along. This is indicated by the color red.

A Pen by HARUN PEHLİVAN on CodePen.

License.

console.clear();
let cvs = document.querySelector('canvas');
let ctx = cvs.getContext('2d');
let w = cvs.width;
let h = cvs.height;
let count = 8;
let clubberW = (w / count) * 1.25;
let clubberH = 1 / count * h;
let adjustedWidth = w - clubberW;
let clubberX = (adjustedWidth / (count - 1));
let overlap = ((clubberW * count) - w) / count * 1.15;
let clubbers = [];
class Clubber {
constructor(index) {
this.index = index;
this.x = index * clubberX;
this.y = index * clubberH;
this.age = index / count;
}
start() {
return this.age * clubberW < overlap;
}
end() {
return this.age * clubberW > clubberW - overlap;
}
}
for (let i = 0; i < count; i++) {
clubbers.push(new Clubber(i));
}
let current = clubbers.length - 1;
let rate = 0.003;
draw();
function draw() {
ctx.clearRect(0, 0, w, h);
for (let i = 0; i < clubbers.length; i++) {
let clubber = clubbers[i];
let prev = i === 0 ? clubbers[clubbers.length - 1] : clubbers[i - 1];
let next = clubbers[(i + 1) % clubbers.length];
ctx.fillStyle = 'white';
ctx.fillRect(clubber.x, clubber.y, clubberW, clubberH);
let progressX = clubber.age * clubberW;
// start
if (i !== 0) {
ctx.fillStyle = (clubber.start() && prev.end()) ? 'red' : '#ddd';
ctx.fillRect(clubber.x, clubber.y, overlap, clubberH);
}
// end
if (i !== clubbers.length - 1) {
ctx.fillStyle = (clubber.end() && next.start()) ? 'red' : '#ddd';
ctx.fillRect(clubber.x + clubberW - overlap, clubber.y, overlap, clubberH);
}
ctx.strokeStyle = 'black';
ctx.lineWidth = 4;
ctx.beginPath();
ctx.moveTo(clubber.x + progressX, clubber.y);
ctx.lineTo(clubber.x + progressX, clubber.y + clubberH);
ctx.stroke();
clubber.age = (clubber.age + rate) % 1;
}
requestAnimationFrame(() => {
draw();
});
}
body {
background: #121212;
overflow: hidden;
}
div {
max-width: 95%;
color: white;
position: absolute;
width: 600px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
&:nth-of-type(1),
&:nth-of-type(2) {
z-index: 9;
&:after {
content: '';
padding-bottom: 100%;
display: block;
}
span {
color: #999;
position: absolute;
transform-origin: 50% 50%;
font-size: 0.8rem;
width: calc(100% - 2rem);
left: 1rem;
text-transform: uppercase;
letter-spacing: 0.025em;
}
}
&:nth-of-type(1) span {
text-align: right;
top: 1rem;
strong {
color: white;
}
}
&:nth-of-type(2) span {
bottom: 1rem;
strong {
color: red;
}
}
&:nth-of-type(3) {
z-index: 1;
}
}
canvas {
height: auto;
width: 100%;
background: black;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment