Compare commits
6 Commits
17a49d8c45
...
589c766d23
Author | SHA1 | Date | |
---|---|---|---|
589c766d23 | |||
fde32a3dc1 | |||
3e95295f0b | |||
ac13f6442a | |||
b1d686596b | |||
604a29e09f |
2
external/libfigure/dance.js
vendored
2
external/libfigure/dance.js
vendored
|
@ -22,7 +22,7 @@ function invertPair(whostr, dialect) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function labelForBeats(beats) {
|
export function labelForBeats(beats) {
|
||||||
if (beats % 16 == 0)
|
if (beats % 16 == 0)
|
||||||
switch (beats / 16) {
|
switch (beats / 16) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
14
external/libfigure/define-figure.js
vendored
14
external/libfigure/define-figure.js
vendored
|
@ -7,7 +7,15 @@
|
||||||
// language construct for defining dance moves
|
// language construct for defining dance moves
|
||||||
// and related support functions for dealing with figures
|
// and related support functions for dealing with figures
|
||||||
|
|
||||||
|
import { formalParamIsDancers } from "./param.js"
|
||||||
import { libfigureObjectCopy, throw_up } from "./util.js"
|
import { libfigureObjectCopy, throw_up } from "./util.js"
|
||||||
|
import {
|
||||||
|
FLATTEN_FORMAT_HTML,
|
||||||
|
FLATTEN_FORMAT_SAFE_TEXT,
|
||||||
|
FLATTEN_FORMAT_UNSAFE_TEXT,
|
||||||
|
Words,
|
||||||
|
words,
|
||||||
|
} from "./words.js";
|
||||||
|
|
||||||
// always freshly allocated
|
// always freshly allocated
|
||||||
function newFigure(optional_progression) {
|
function newFigure(optional_progression) {
|
||||||
|
@ -18,7 +26,7 @@ function newFigure(optional_progression) {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
function figureBeats(f) {
|
export function figureBeats(f) {
|
||||||
var defaultBeats = 8
|
var defaultBeats = 8
|
||||||
if (!f.move) return defaultBeats
|
if (!f.move) return defaultBeats
|
||||||
var idx = find_parameter_index_by_name("beats", parameters(f.move))
|
var idx = find_parameter_index_by_name("beats", parameters(f.move))
|
||||||
|
@ -106,7 +114,7 @@ function find_parameter_index_by_name(name, parameters) {
|
||||||
|
|
||||||
// ================
|
// ================
|
||||||
|
|
||||||
function parameter_strings(move, parameter_values, dialect) {
|
export function parameter_strings(move, parameter_values, dialect) {
|
||||||
return parameter_strings_or_words(move, parameter_values, dialect, false)
|
return parameter_strings_or_words(move, parameter_values, dialect, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,7 +181,7 @@ function heyLengthSubstitution(hey_length, dialect) {
|
||||||
|
|
||||||
var moveSubstitutionPercentSRegexp = / *%S */g
|
var moveSubstitutionPercentSRegexp = / *%S */g
|
||||||
|
|
||||||
function moveSubstitution(move_term, dialect) {
|
export function moveSubstitution(move_term, dialect) {
|
||||||
var sub = moveSubstitutionWithEscape(move_term, dialect)
|
var sub = moveSubstitutionWithEscape(move_term, dialect)
|
||||||
return sub.replace(moveSubstitutionPercentSRegexp, " ").trim()
|
return sub.replace(moveSubstitutionPercentSRegexp, " ").trim()
|
||||||
}
|
}
|
||||||
|
|
3
external/libfigure/figure.js
vendored
3
external/libfigure/figure.js
vendored
|
@ -13,7 +13,10 @@ import {
|
||||||
defineRelatedMove2Way,
|
defineRelatedMove2Way,
|
||||||
goodBeatsMinMaxFn,
|
goodBeatsMinMaxFn,
|
||||||
goodBeatsMinFn,
|
goodBeatsMinFn,
|
||||||
|
moveSubstitution,
|
||||||
|
parameter_strings,
|
||||||
} from "./define-figure.js"
|
} from "./define-figure.js"
|
||||||
|
import { comma, words } from "./words.js";
|
||||||
|
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
// ALLEMANDE //
|
// ALLEMANDE //
|
||||||
|
|
10
external/libfigure/move.js
vendored
10
external/libfigure/move.js
vendored
|
@ -8,6 +8,8 @@
|
||||||
// Properties of moves (strings).
|
// Properties of moves (strings).
|
||||||
// Few dependencies to the rest of the system.
|
// Few dependencies to the rest of the system.
|
||||||
|
|
||||||
|
import { deAliasMove } from "./define-figure.js";
|
||||||
|
|
||||||
var moveCaresAboutRotationsHash = {
|
var moveCaresAboutRotationsHash = {
|
||||||
"do si do": true,
|
"do si do": true,
|
||||||
allemande: true,
|
allemande: true,
|
||||||
|
@ -17,7 +19,7 @@ var moveCaresAboutRotationsHash = {
|
||||||
"mad robin": true,
|
"mad robin": true,
|
||||||
}
|
}
|
||||||
// it now seems to me that this should be defined by defineFigure -dm 03-07-2017
|
// it now seems to me that this should be defined by defineFigure -dm 03-07-2017
|
||||||
function moveCaresAboutRotations(move) {
|
export function moveCaresAboutRotations(move) {
|
||||||
return moveCaresAboutRotationsHash[deAliasMove(move)]
|
return moveCaresAboutRotationsHash[deAliasMove(move)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +31,7 @@ var moveCaresAboutPlacesHash = {
|
||||||
"box circulate": true,
|
"box circulate": true,
|
||||||
}
|
}
|
||||||
// it now seems to me that this should be defined by defineFigure -dm 03-07-2017
|
// it now seems to me that this should be defined by defineFigure -dm 03-07-2017
|
||||||
function moveCaresAboutPlaces(move) {
|
export function moveCaresAboutPlaces(move) {
|
||||||
return moveCaresAboutPlacesHash[deAliasMove(move)]
|
return moveCaresAboutPlacesHash[deAliasMove(move)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +74,7 @@ export const degreesToWords = function(degrees, optional_move) {
|
||||||
return degrees.toString() + " degrees"
|
return degrees.toString() + " degrees"
|
||||||
}
|
}
|
||||||
|
|
||||||
function degreesToRotations(degrees) {
|
export function degreesToRotations(degrees) {
|
||||||
if (degrees) {
|
if (degrees) {
|
||||||
return degrees2rotations[degrees] || degrees.toString() + " degrees"
|
return degrees2rotations[degrees] || degrees.toString() + " degrees"
|
||||||
} else {
|
} else {
|
||||||
|
@ -80,7 +82,7 @@ function degreesToRotations(degrees) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function degreesToPlaces(degrees) {
|
export function degreesToPlaces(degrees) {
|
||||||
if (degrees) {
|
if (degrees) {
|
||||||
return degrees2places[degrees] || degrees.toString() + " degrees"
|
return degrees2places[degrees] || degrees.toString() + " degrees"
|
||||||
} else {
|
} else {
|
||||||
|
|
10
external/libfigure/param.js
vendored
10
external/libfigure/param.js
vendored
|
@ -11,7 +11,13 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import { throw_up } from "./util.js"
|
import { throw_up } from "./util.js"
|
||||||
import { chooser } from "./chooser.js"
|
import { chooser, dancerMenuForChooser } from "./chooser.js"
|
||||||
|
import {
|
||||||
|
degreesToPlaces,
|
||||||
|
degreesToRotations,
|
||||||
|
moveCaresAboutPlaces,
|
||||||
|
moveCaresAboutRotations,
|
||||||
|
} from "./move.js";
|
||||||
|
|
||||||
const __params = {}
|
const __params = {}
|
||||||
|
|
||||||
|
@ -453,7 +459,7 @@ defineParam("lead_dancer_l1", {
|
||||||
ui: "chooser_dancer",
|
ui: "chooser_dancer",
|
||||||
})
|
})
|
||||||
|
|
||||||
function formalParamIsDancers(param) {
|
export function formalParamIsDancers(param) {
|
||||||
// harder to maintain implementation:
|
// harder to maintain implementation:
|
||||||
// return ['who', 'who2', 'whom', 'lead'].indexOf(param.name) >= 0;
|
// return ['who', 'who2', 'whom', 'lead'].indexOf(param.name) >= 0;
|
||||||
return !!dancerMenuForChooser(param.ui)
|
return !!dancerMenuForChooser(param.ui)
|
||||||
|
|
2
external/libfigure/words.js
vendored
2
external/libfigure/words.js
vendored
|
@ -6,7 +6,7 @@ import {
|
||||||
import { dancers } from "./chooser.js"
|
import { dancers } from "./chooser.js"
|
||||||
import { moves } from "./define-figure.js"
|
import { moves } from "./define-figure.js"
|
||||||
|
|
||||||
function Words(arr) {
|
export function Words(arr) {
|
||||||
this.arr = arr
|
this.arr = arr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,15 @@
|
||||||
background-color: hsl(180, 90%, 70%);
|
background-color: hsl(180, 90%, 70%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.move {
|
||||||
|
list-style-type: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.currentMove {
|
||||||
|
background-color: yellow;
|
||||||
|
list-style-type: '▶';
|
||||||
|
}
|
||||||
|
|
||||||
.source {
|
.source {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
@ -536,7 +536,7 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
||||||
|
|
||||||
function danceAsLowLevelMoves(moves: Move[], startingPos: Map<DancerIdentity, SemanticPosition>): Map<DancerIdentity, LowLevelMove[]> {
|
function danceAsLowLevelMoves(moves: Move[], startingPos: Map<DancerIdentity, SemanticPosition>): Map<DancerIdentity, LowLevelMove[]> {
|
||||||
const res = new Map<DancerIdentity, LowLevelMove[]>([...startingPos.keys()].map(id => [id, []]));
|
const res = new Map<DancerIdentity, LowLevelMove[]>([...startingPos.keys()].map(id => [id, []]));
|
||||||
let currentPos = startingPos;
|
let currentPos = new Map<DancerIdentity, SemanticPosition>(startingPos);
|
||||||
for (const move of moves) {
|
for (const move of moves) {
|
||||||
const newMoves = moveAsLowLevelMoves(move, currentPos);
|
const newMoves = moveAsLowLevelMoves(move, currentPos);
|
||||||
for (const [id, newMoveList] of newMoves.entries()) {
|
for (const [id, newMoveList] of newMoves.entries()) {
|
||||||
|
|
107
www/js/main.ts
107
www/js/main.ts
|
@ -2,8 +2,10 @@ import * as animation from "./animation.js";
|
||||||
import * as interpreter from "./interpreter.js";
|
import * as interpreter from "./interpreter.js";
|
||||||
import * as renderer from "./renderer.js";
|
import * as renderer from "./renderer.js";
|
||||||
import { DancerIdentity } from "./danceCommon.js";
|
import { DancerIdentity } from "./danceCommon.js";
|
||||||
import { LibFigureDance, Move } from "./libfigureMapper.js";
|
import { LibFigureDance, LibFigureMove, Move } from "./libfigureMapper.js";
|
||||||
import { animateLowLevelMove, LowLevelMove } from "./lowLevelMove.js";
|
import { animateLowLevelMove, LowLevelMove } from "./lowLevelMove.js";
|
||||||
|
import { figureBeats, figureToHtml } from "./libfigure/define-figure.js";
|
||||||
|
import { labelForBeats } from "./libfigure/dance.js";
|
||||||
|
|
||||||
const body = document.querySelector('body')!;
|
const body = document.querySelector('body')!;
|
||||||
|
|
||||||
|
@ -79,6 +81,10 @@ progressionLabel.htmlFor = 'progression';
|
||||||
const playButton = document.createElement('button');
|
const playButton = document.createElement('button');
|
||||||
playButton.innerText = "Play";
|
playButton.innerText = "Play";
|
||||||
|
|
||||||
|
const movesList = document.createElement('ul');
|
||||||
|
|
||||||
|
wrapperDiv.appendChild(movesList);
|
||||||
|
wrapperDiv.appendChild(document.createElement('br'));
|
||||||
wrapperDiv.appendChild(bpmSelector);
|
wrapperDiv.appendChild(bpmSelector);
|
||||||
wrapperDiv.appendChild(bpmLabel);
|
wrapperDiv.appendChild(bpmLabel);
|
||||||
wrapperDiv.appendChild(playButton);
|
wrapperDiv.appendChild(playButton);
|
||||||
|
@ -89,14 +95,25 @@ wrapperDiv.appendChild(document.createElement('br'));
|
||||||
wrapperDiv.appendChild(beatSliderLabel);
|
wrapperDiv.appendChild(beatSliderLabel);
|
||||||
wrapperDiv.appendChild(beatDisplay);
|
wrapperDiv.appendChild(beatDisplay);
|
||||||
|
|
||||||
beatSlider.addEventListener('input', (ev) => {
|
function drawAtCurrentBeat() {
|
||||||
r.drawSetsWithTrails(beatSlider.valueAsNumber, progressionSelector.valueAsNumber);
|
r.drawSetsWithTrails(beatSlider.valueAsNumber, progressionSelector.valueAsNumber);
|
||||||
|
|
||||||
|
const currentMoves = movesList.getElementsByClassName('currentMove');
|
||||||
|
for (let i = 0; i < currentMoves.length; i++) {
|
||||||
|
currentMoves[i].classList.remove('currentMove');
|
||||||
|
}
|
||||||
|
movesList.getElementsByClassName('moveForBeat_' + Math.floor(beatSlider.valueAsNumber))[0]
|
||||||
|
.classList.add('currentMove');
|
||||||
|
}
|
||||||
|
|
||||||
|
beatSlider.addEventListener('input', (ev) => {
|
||||||
|
drawAtCurrentBeat();
|
||||||
beatDisplay.innerText = beatSlider.valueAsNumber.toFixed(1);
|
beatDisplay.innerText = beatSlider.valueAsNumber.toFixed(1);
|
||||||
restartAnimation(false);
|
restartAnimation(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
progressionSelector.addEventListener('input', (ev) => {
|
progressionSelector.addEventListener('input', (ev) => {
|
||||||
r.drawSetsWithTrails(beatSlider.valueAsNumber, progressionSelector.valueAsNumber);
|
drawAtCurrentBeat();
|
||||||
restartAnimation(false);
|
restartAnimation(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -131,7 +148,61 @@ playButton.addEventListener('click', (ev) => {
|
||||||
});
|
});
|
||||||
bpmSelector.addEventListener('change', (ev) => {
|
bpmSelector.addEventListener('change', (ev) => {
|
||||||
restartAnimation(false);
|
restartAnimation(false);
|
||||||
})
|
});
|
||||||
|
|
||||||
|
// Two Hearts in Time by Isaac Banner. Selected arbitrarily.
|
||||||
|
const exampleDance: LibFigureDance = [{ "parameter_values": [true, 8], "move": "petronella" }, { "parameter_values": [true, 8], "move": "petronella" }, { "parameter_values": ["neighbors", "balance", 16], "move": "swing" }, { "parameter_values": ["ladles", true, 540, 8], "move": "allemande" }, { "parameter_values": ["partners", "none", 8], "move": "swing" }, { "parameter_values": ["gentlespoons", 360, 6], "move": "mad robin" }, { "parameter_values": [true, 270, 6], "move": "circle" }, { "parameter_values": ["partners", 4], "move": "California twirl", "progression": 1 }];
|
||||||
|
|
||||||
|
const dialect = {
|
||||||
|
moves: {},
|
||||||
|
dancers: {
|
||||||
|
ladle: "robin",
|
||||||
|
ladles: "robins",
|
||||||
|
gentlespoon: "lark",
|
||||||
|
gentlespoons: "larks",
|
||||||
|
"first ladle": "first robin",
|
||||||
|
"second ladle": "second robin",
|
||||||
|
"first gentlespoon": "first lark",
|
||||||
|
"second gentlespoon": "second lark",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let dance: LibFigureDance;
|
||||||
|
function buildMovesList() {
|
||||||
|
removeAllChildNodes(movesList);
|
||||||
|
|
||||||
|
let currentBeat: number = 0;
|
||||||
|
let lastItem: HTMLLIElement | undefined;
|
||||||
|
for (const figure of dance) {
|
||||||
|
const startBeat = currentBeat;
|
||||||
|
currentBeat += figureBeats(figure);
|
||||||
|
const moveItem = document.createElement('li');
|
||||||
|
moveItem.innerHTML = "[" + labelForBeats(Math.floor(startBeat / 16) * 16) + " "
|
||||||
|
+ "(" + startBeat + "-" + currentBeat + ")] "
|
||||||
|
+ figureToHtml(figure, dialect);
|
||||||
|
moveItem.classList.add('move');
|
||||||
|
for (let beat = startBeat; beat < currentBeat; beat++) {
|
||||||
|
moveItem.classList.add('moveForBeat_' + beat);
|
||||||
|
}
|
||||||
|
if (startBeat === 0) moveItem.classList.add('currentMove');
|
||||||
|
moveItem.addEventListener('click', (ev) => {
|
||||||
|
setBeat(startBeat);
|
||||||
|
restartAnimation(false);
|
||||||
|
});
|
||||||
|
lastItem = moveItem;
|
||||||
|
movesList.appendChild(moveItem);
|
||||||
|
}
|
||||||
|
if (lastItem) {
|
||||||
|
lastItem.classList.add('moveForBeat_' + currentBeat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setBeat(beat: number) {
|
||||||
|
beatSlider.value = beat.toString();
|
||||||
|
beatDisplay.innerText = beat.toFixed(1);
|
||||||
|
|
||||||
|
drawAtCurrentBeat();
|
||||||
|
}
|
||||||
function playAnimation(bpm: number, start: number, end: number) {
|
function playAnimation(bpm: number, start: number, end: number) {
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
const msPerBeat = (60 * 1000) / bpm;
|
const msPerBeat = (60 * 1000) / bpm;
|
||||||
|
@ -153,10 +224,7 @@ function playAnimation(bpm: number, start: number, end: number) {
|
||||||
changedProgression = true;
|
changedProgression = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
beatSlider.value = beat.toString();
|
setBeat(beat);
|
||||||
beatDisplay.innerText = beat.toFixed(1);
|
|
||||||
|
|
||||||
r.drawSetsWithTrails(beat, progressionSelector.valueAsNumber);
|
|
||||||
if (changedProgression) {
|
if (changedProgression) {
|
||||||
restartAnimation(true);
|
restartAnimation(true);
|
||||||
return;
|
return;
|
||||||
|
@ -167,9 +235,6 @@ function playAnimation(bpm: number, start: number, end: number) {
|
||||||
anim();
|
anim();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Two Hearts in Time by Isaac Banner. Selected arbitrarily.
|
|
||||||
const exampleDance: LibFigureDance = [{ "parameter_values": [true, 8], "move": "petronella" }, { "parameter_values": [true, 8], "move": "petronella" }, { "parameter_values": ["neighbors", "balance", 16], "move": "swing" }, { "parameter_values": ["ladles", true, 540, 8], "move": "allemande" }, { "parameter_values": ["partners", "none", 8], "move": "swing" }, { "parameter_values": ["gentlespoons", 360, 6], "move": "mad robin" }, { "parameter_values": [true, 270, 6], "move": "circle" }, { "parameter_values": ["partners", 4], "move": "California twirl", "progression": 1 }];
|
|
||||||
|
|
||||||
const danceJsonArea = document.createElement('textarea');
|
const danceJsonArea = document.createElement('textarea');
|
||||||
danceJsonArea.value = JSON.stringify(exampleDance, undefined, 2);
|
danceJsonArea.value = JSON.stringify(exampleDance, undefined, 2);
|
||||||
danceJsonArea.rows = 15;
|
danceJsonArea.rows = 15;
|
||||||
|
@ -180,8 +245,9 @@ wrapperDiv.appendChild(document.createElement('br'));
|
||||||
wrapperDiv.appendChild(danceJsonArea);
|
wrapperDiv.appendChild(danceJsonArea);
|
||||||
wrapperDiv.appendChild(loadDanceButton);
|
wrapperDiv.appendChild(loadDanceButton);
|
||||||
|
|
||||||
loadDanceButton.addEventListener('click', (ev) => {
|
const table = document.createElement('table');
|
||||||
const dance: LibFigureDance = JSON.parse(danceJsonArea.value);
|
function loadDance() {
|
||||||
|
dance = JSON.parse(danceJsonArea.value);
|
||||||
r.animation = interpreter.loadDance(dance);
|
r.animation = interpreter.loadDance(dance);
|
||||||
if (cancelAnim !== undefined) {
|
if (cancelAnim !== undefined) {
|
||||||
cancelAnimationFrame(cancelAnim);
|
cancelAnimationFrame(cancelAnim);
|
||||||
|
@ -192,7 +258,10 @@ loadDanceButton.addEventListener('click', (ev) => {
|
||||||
beatDisplay.innerText = '0.0';
|
beatDisplay.innerText = '0.0';
|
||||||
r.drawSetsWithTrails(0);
|
r.drawSetsWithTrails(0);
|
||||||
buildDebugTable();
|
buildDebugTable();
|
||||||
});
|
buildMovesList();
|
||||||
|
}
|
||||||
|
loadDanceButton.addEventListener('click', loadDance);
|
||||||
|
loadDance();
|
||||||
|
|
||||||
function createJsonCell(content: any, rowSpan?: number, id?: DancerIdentity) {
|
function createJsonCell(content: any, rowSpan?: number, id?: DancerIdentity) {
|
||||||
const cell = document.createElement('td');
|
const cell = document.createElement('td');
|
||||||
|
@ -247,13 +316,15 @@ showDebugLabel.htmlFor = 'showDebug';
|
||||||
body.appendChild(showDebug);
|
body.appendChild(showDebug);
|
||||||
body.appendChild(showDebugLabel);
|
body.appendChild(showDebugLabel);
|
||||||
|
|
||||||
const table = document.createElement('table');
|
|
||||||
table.id = 'debug'
|
table.id = 'debug'
|
||||||
|
|
||||||
function buildDebugTable() {
|
function removeAllChildNodes(html: HTMLElement) {
|
||||||
while (table.childNodes.length > 0) {
|
while (html.childNodes.length > 0) {
|
||||||
table.removeChild(table.childNodes[table.childNodes.length - 1]);
|
html.removeChild(html.childNodes[html.childNodes.length - 1]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
function buildDebugTable() {
|
||||||
|
removeAllChildNodes(table);
|
||||||
|
|
||||||
const headerRow = document.createElement('tr');
|
const headerRow = document.createElement('tr');
|
||||||
const roles = [DancerIdentity.OnesLark, DancerIdentity.OnesRobin,
|
const roles = [DancerIdentity.OnesLark, DancerIdentity.OnesRobin,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user