massi-world-scratch

a slew of pages that need no compilation
Log | Files | Refs

commit 387dc6c50d6563929262461b7e534ef08bca4ef1
Author: massi <git@massi.world>
Date:   Sun, 11 Jan 2026 23:08:37 -0800

triads

Diffstat:
Aindex.html | 8++++++++
Atriads/index.html | 15+++++++++++++++
Atriads/main.js | 28++++++++++++++++++++++++++++
Atriads/main.ts | 25+++++++++++++++++++++++++
Atriads/style.css | 29+++++++++++++++++++++++++++++
5 files changed, 105 insertions(+), 0 deletions(-)

diff --git a/index.html b/index.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<html> + <body> + <ul> + <li><a href="https://scratch.massi.world/triads">triad exercise</a></li> + </ul> + </body> +</html> diff --git a/triads/index.html b/triads/index.html @@ -0,0 +1,15 @@ +<html> + <head> + <script src="./main.js"></script> + <link rel="stylesheet" href="./style.css" /> + </head> + <body> + <h1>triad voice leading exercise</h1> + <h2>from mick goodrick's Advancing Guitarist</h2> + <div id="desc"> + Find the minimum difference between each triad in order to play a good + voice leading that goes through every possible triad. + </div> + <div id="chart"></div> + </body> +</html> diff --git a/triads/main.js b/triads/main.js @@ -0,0 +1,28 @@ +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; +var NOTES = ["A", "Bb", "B", "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab"]; +var QUALITIES = ["", "-", "°", "+"]; +var POSSIBILITIES = NOTES.reduce(function (accum, note) { + return __spreadArray(__spreadArray([], accum, true), QUALITIES.map(function (q) { return note + q; }), true); +}, []); +var bag = new Array(POSSIBILITIES.length).fill(0).map(function (_, i) { return i; }); +var result = []; +while (bag.length > 0) { + var bagIdx = Math.floor(Math.random() * bag.length); + var possibilitiesIdx = bag[bagIdx]; + result.push(POSSIBILITIES[possibilitiesIdx]); + bag.splice(bagIdx, 1); +} +document.addEventListener("DOMContentLoaded", function () { + document.getElementById("chart").innerHTML = result + .map(function (note) { return "<code>".concat(note, "</code>"); }) + .join(""); +}); +// the other mode would be 1-7 in a given KEY, starting at a given INVERSION. diff --git a/triads/main.ts b/triads/main.ts @@ -0,0 +1,25 @@ +const NOTES = ["A", "Bb", "B", "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab"]; + +const QUALITIES = ["", "-", "°", "+"]; + +const POSSIBILITIES = NOTES.reduce<string[]>((accum, note) => { + return [...accum, ...QUALITIES.map((q) => note + q)]; +}, []); + +const bag = new Array(POSSIBILITIES.length).fill(0).map((_, i) => i); + +let result: string[] = []; +while (bag.length > 0) { + const bagIdx = Math.floor(Math.random() * bag.length); + const possibilitiesIdx = bag[bagIdx]; + result.push(POSSIBILITIES[possibilitiesIdx]); + bag.splice(bagIdx, 1); +} + +document.addEventListener("DOMContentLoaded", () => { + document.getElementById("chart")!.innerHTML = result + .map((note) => `<code>${note}</code>`) + .join(""); +}); + +// the other mode would be 1-7 in a given KEY, starting at a given INVERSION. diff --git a/triads/style.css b/triads/style.css @@ -0,0 +1,29 @@ +#chart { + display: flex; + flex-wrap: wrap; + padding: 1rem; +} + +h1, +h2 { + text-align: center; +} + +#desc { + max-width: 40rem; + margin: auto; +} + +code { + font-size: 1.5rem; + width: 12.5%; + box-sizing: border-box; + text-align: center; + padding: 1rem; +} + +@media (max-aspect-ratio: 1/1) { + code { + width: 25%; + } +}