Skip to content

Commit 2299acf

Browse files
committed
Updated demo
1 parent 4691526 commit 2299acf

File tree

8 files changed

+295
-184
lines changed

8 files changed

+295
-184
lines changed

assets/word-buffers.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"nounCtx": {
3+
"canvas": "nounCanvas",
4+
"order": 1,
5+
"scrollSpeed": 1,
6+
"cursor": ["cursorX", "cursorY"],
7+
"cursorOffset": [0, -20]
8+
},
9+
"adjCtx": {
10+
"canvas": "adjCanvas",
11+
"order": 0,
12+
"scrollSpeed": 0.8,
13+
"cursor": ["adjCursorX", "adjCursorY"],
14+
"cursorOffset": [0, 0]
15+
}
16+
}

assets/word-styles.json

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,62 @@
11
{
2-
"noun": ["", "bold", [100, 300], "Arial", ""],
3-
"verb": ["italic", "", [50, 350], "Arial", "uppercase"],
4-
"adjective": ["italic", "bold", [150, 400], "Times New Roman", ""],
5-
"adverb": ["italic", "bold", [100, 300], "Times New Roman", ""],
6-
"expression": ["", "", [100, 400], "Comic Sans MS", "uppercase"],
7-
"default": ["", "", [100, 450], "Times New Roman", ""]
2+
"noun": {
3+
"buffer": "nounCtx",
4+
"style": ["", "bold", [100, 300], "Arial", "", "black", "alphabetic"],
5+
"offsetRatio": [1.0, 0.0]
6+
},
7+
"plural": {
8+
"buffer": "nounCtx",
9+
"style": ["", "bold", [50, 150], "Arial", "", "black", "alphabetic"],
10+
"offsetRatio": [1.0, 0.0]
11+
},
12+
"pronoun": {
13+
"buffer": "adjCtx",
14+
"style": ["", "bold", [200, 400], "Arial", "uppercase", "#990000", "bottom"],
15+
"offsetRatio": [1.0, 0.5]
16+
},
17+
"verb": {
18+
"buffer": "nounCtx",
19+
"style": ["italic", "", [50, 350], "Arial", "uppercase", "black", "alphabetic"],
20+
"offsetRatio": [1.0, 0.0]
21+
},
22+
"adjective": {
23+
"buffer": "adjCtx",
24+
"style": ["italic", "bold", [400, 600], "Times New Roman", "", "#990000", "alphabetic"],
25+
"offsetRatio": [1.0, 0.0]
26+
},
27+
"adverb": {
28+
"buffer": "adjCtx",
29+
"style": ["italic", "bold", [300, 500], "Times New Roman", "", "#990000", "alphabetic"],
30+
"offsetRatio": [1.0, 0.0]
31+
},
32+
"conjunction": {
33+
"buffer": "nounCtx",
34+
"style": ["", "", [50, 100], "Arial", "", "black", "alphabetic"],
35+
"offsetRatio": [0, 3.0]
36+
},
37+
"determiner": {
38+
"buffer": "nounCtx",
39+
"style": ["", "", [50, 100], "Arial", "", "black", "alphabetic"],
40+
"offsetRatio": [0, 3.0]
41+
},
42+
"preposition": {
43+
"buffer": "nounCtx",
44+
"style": ["", "", [50, 100], "Arial", "", "black", "alphabetic"],
45+
"offsetRatio": [0, 3.0]
46+
},
47+
"expression": {
48+
"buffer": "nounCtx",
49+
"style": ["", "", [100, 400], "Comic Sans MS", "uppercase", "black", "alphabetic"],
50+
"offsetRatio": [1.0, 0.0]
51+
},
52+
"questionword": {
53+
"buffer": "adjCtx",
54+
"style": ["", "", [200, 300], "Comic Sans MS", "", "#bb0000", "alphabetic"],
55+
"offsetRatio": [1, 1]
56+
},
57+
"default": {
58+
"buffer": "nounCtx",
59+
"style": ["", "", [50, 250], "Times New Roman", "", "black", "alphabetic"],
60+
"offsetRatio": [1.0, 0.0]
61+
}
862
}

src-words2music/audio.js

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ export async function loadIntsruments() {
1515
let lastSoundTime = 0;
1616

1717
export async function playDotSound(y, instrument, scale = null, length = "8n", volume = 0, snapTime = null) {
18-
if (Tone.now() - lastSoundTime < 0.03) {
18+
if (Tone.now() - lastSoundTime < 0.02) {
1919
console.log("Too soon to play sound");
2020
return;
2121
}
22+
lastSoundTime = Tone.now();
2223

2324
// Handle frequency
2425
var frequency;
@@ -70,23 +71,6 @@ export async function playDotSound(y, instrument, scale = null, length = "8n", v
7071
instrument.triggerAttackRelease(frequency, length, time);
7172
}
7273

73-
export async function playBaseSound(dot) {
74-
let time;
75-
// if (!dot.prevCollidedWithGround) {
76-
// time = snap2subdivision("16n");
77-
// // const drift = Tone.now() - time;
78-
// // console.log("Drift:", drift);
79-
// // Tone.Transport.seconds += drift;
80-
// } else {
81-
// // Ground bounce: snap clean to 4n
82-
// time = snap2subdivision("4n");
83-
// }
84-
time = snap2subdivision("4n");
85-
86-
// dot.lastDownbeatTime = time; // update anchor
87-
synth.triggerAttackRelease("C3", "8n", time);
88-
}
89-
9074
function snap2subdivision(subdivision = "8n", tol = 0.03) {
9175
const now = Tone.now();
9276
const nextTime = Tone.Transport.nextSubdivision(subdivision);

src-words2music/dot.js

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@ export class Dot {
22
constructor(x, radius) {
33
this.x = x;
44
this.y = 0;
5-
this.u = 1;
5+
this.u = 0.3;
66
this.v = 0;
7+
this.r = radius;
8+
this.g = 12;
9+
this.viscosity = 4;
710
this.xPrev = this.x;
811
this.yPrev = this.y;
912
this.uPrev = this.u;
1013
this.vPrev = this.v;
1114
this.xTarget = this.x;
1215
this.yTarget = this.y;
13-
this.r = radius;
1416
this.colour = "blue";
1517
this.hasCollided = false;
1618
this.hasCollidedWithGround = false;
1719
this.prevCollidedWithGround = false;
20+
this.inSlowMo = false;
1821
this.inFloatingMode = false;
1922
}
2023

@@ -32,7 +35,10 @@ export class Dot {
3235
this.xTarget = this.x + this.u * deltaTime;
3336

3437
// y-motion
35-
if (this.inFloatingMode) {
38+
if (this.inSlowMo) {
39+
this.v -= this.viscosity * this.v * deltaTime;
40+
this.v += (0.2 * this.g) * deltaTime;
41+
} else if (this.inFloatingMode) {
3642
this.v += (-0.5 * this.g) * deltaTime;
3743
} else {
3844
this.v += this.g * deltaTime;
@@ -45,22 +51,31 @@ export class Dot {
4551
// Check for collision
4652
const collisionResult =
4753
checkPathCollision(collisionImgBuffer, this.xPrev, this.yPrev, this.xTarget, this.yTarget, this.r, this.xScale, this.yScale);
48-
this.hasCollided = collisionResult.hasCollided;
54+
this.hasCollided = collisionResult.hasCollided > 0;
4955
if (this.hasCollided) {
5056
this.prevCollidedWithGround = false;
5157
}
5258
const yCollision = collisionResult.y;
5359

5460
// No collision
55-
if (!this.hasCollided) {
61+
if (collisionResult.hasCollided == 0) {
62+
this.hasCollided = false;
5663
this.x = this.xTarget;
5764
this.y = this.yTarget;
5865
this.inFloatingMode = false;
66+
this.inSlowMo = false;
67+
return;
68+
} else if (collisionResult.hasCollided == 2) {
69+
this.hasCollided = true;
70+
this.x = this.xTarget;
71+
this.y = this.yTarget;
72+
this.inFloatingMode = false;
73+
this.inSlowMo = true;
5974
return;
6075
}
6176

6277
// Collision detected, but in floating mode, so no need to push out
63-
if (this.inFloatingMode) {
78+
if (this.inFloatingMode || this.inSlowMo) {
6479
this.x = this.xTarget;
6580
this.y = this.yTarget;
6681
return;
@@ -70,12 +85,21 @@ export class Dot {
7085
const xTargetCollision = this.xTarget;
7186
const yTargetCollision = yCollision - (this.yTarget - yCollision);
7287

73-
if (checkCollision(collisionImgBuffer, xTargetCollision, yTargetCollision, this.r, this.xScale, this.yScale)) {
88+
const origCollisionResult = checkCollision(
89+
collisionImgBuffer, xTargetCollision, yTargetCollision,
90+
this.r, this.xScale, this.yScale);
91+
if (origCollisionResult == 1) {
7492
// Cannot push out of collision: enter floating mode
7593
this.x = this.xTarget;
7694
this.y = this.yTarget;
7795
this.inFloatingMode = true;
7896
return;
97+
} else if (origCollisionResult == 2) {
98+
// Soft collision: enter floating mode
99+
this.x = this.xTarget;
100+
this.y = this.yTarget;
101+
this.inSlowMo = true;
102+
return;
79103
}
80104

81105
if (this.yTarget < this.yPrev) {
@@ -136,19 +160,6 @@ export class Dot {
136160
ctx.arc(this.x * this.xScale, this.y * this.yScale, this.r, 0, Math.PI * 2);
137161
ctx.fill();
138162
}
139-
140-
async playSound(y, snapPitch = true) {
141-
Tone.start();
142-
const minPitch = 110; // lowest frequency (Hz)
143-
const maxPitch = 880; // highest frequency (Hz)
144-
145-
const normFactor = Math.max(Math.min(1 - (y / this.height), 1), 0); // 1 at top, 0 at bottom
146-
var frequency = minPitch + normFactor * (maxPitch - minPitch);
147-
if (snapPitch) {
148-
frequency = noteId2frequency(frequency2noteId(frequency, true));
149-
}
150-
synth.triggerAttackRelease(frequency, "8n");
151-
}
152163
}
153164

154165
function checkCollision(collisionImgBuffer, dotX, dotY, radius, xScale, yScale) {
@@ -160,19 +171,25 @@ function checkCollision(collisionImgBuffer, dotX, dotY, radius, xScale, yScale)
160171

161172
// Make sure sample inside canvas
162173
if (sampleX < 0 || sampleX >= canvas.width || sampleY < 0 || sampleY >= canvas.height) continue;
163-
let pixel;
174+
let alpha;
175+
let r;
164176
try {
165177
const alphaId = (sampleY * collisionImgBuffer.width + sampleX) * 4 + 3;
166-
pixel = collisionImgBuffer.data[alphaId];
178+
alpha = collisionImgBuffer.data[alphaId];
179+
const rId = (sampleY * collisionImgBuffer.width + sampleX) * 4;
180+
r = collisionImgBuffer.data[rId];
167181
} catch (e) {
168182
console.error("Error getting pixel data at ", sampleX, sampleY, ": ", e);
169183
}
170184

171-
if (pixel > 0) {
172-
return true; // collision detected
185+
if (alpha > 0) {
186+
if (r > 50) {
187+
return 2; // soft collision
188+
}
189+
return 1; // hard collision
173190
}
174191
}
175-
return false; // no collision
192+
return 0; // no collision
176193
}
177194

178195
function checkPathCollision(collisionImgBuffer, startX, startY, endX, endY, radius, xScale, yScale, steps = 6) {
@@ -187,11 +204,12 @@ function checkPathCollision(collisionImgBuffer, startX, startY, endX, endY, radi
187204
continue;
188205
}
189206

190-
if (checkCollision(collisionImgBuffer, x, y, radius, xScale, yScale)) {
191-
return { hasCollided: true, x: prevX, y: prevY }
207+
const collisionResult = checkCollision(collisionImgBuffer, x, y, radius, xScale, yScale)
208+
if (collisionResult > 0) {
209+
return { hasCollided: collisionResult, x: prevX, y: prevY }
192210
}
193211
prevX = x;
194212
prevY = y;
195213
}
196-
return { hasCollided: false, x: endX, y: endY }
214+
return { hasCollided: 0, x: endX, y: endY }
197215
}

0 commit comments

Comments
 (0)