Compare commits

...

2 Commits

4 changed files with 138 additions and 39 deletions

View File

@ -260,16 +260,23 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
withPos: SemanticPosition & { setOffset: number, lineOffset: number }, withPos: SemanticPosition & { setOffset: number, lineOffset: number },
withId: common.ExtendedDancerIdentity, withId: common.ExtendedDancerIdentity,
around: CircleSideOrCenter, around: CircleSideOrCenter,
}) => LowLevelMove[]), meanwhileFunc?: ((arg: {
id: DancerIdentity,
startPos: SemanticPosition,
}) => LowLevelMove[])): Map<DancerIdentity, LowLevelMove[]> { }) => LowLevelMove[])): Map<DancerIdentity, LowLevelMove[]> {
return handleMove(({ id, startPos }) => { return handleMove(({ id, startPos }) => {
const withId = findPairOpposite(who, id); const withId = findPairOpposite(who, id);
if (!withId) { if (!withId) {
return combine([{ if (meanwhileFunc) {
beats: move.beats, return meanwhileFunc({ id, startPos });
startPosition: { ...startPos, hands: undefined }, } else {
endPosition: { ...startPos, hands: undefined }, return combine([{
movementPattern: { kind: SemanticAnimationKind.StandStill }, beats: move.beats,
}]); startPosition: { ...startPos, hands: undefined },
endPosition: { ...startPos, hands: undefined },
movementPattern: { kind: SemanticAnimationKind.StandStill },
}]);
}
} }
const withPos = getPosFor(withId); const withPos = getPosFor(withId);
const setDifference = withPos.setOffset - (startPos.setOffset ?? 0); const setDifference = withPos.setOffset - (startPos.setOffset ?? 0);
@ -450,20 +457,27 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
}); });
case "mad robin": case "mad robin":
return handleCircleMove(({ startPos }) => { if (move.parameters.circling !== 360) {
// TODO Read who of mad robin to decide direction? throw new Error("mad robin circling not exactly once is unsupported.");
const startAndEndPos = { }
...startPos,
facing: startPos.which.isLeft() ? Facing.Right : Facing.Left, return handleCircleMove(({ id, startPos }) => {
hands: undefined, // Read who of mad robin to decide direction.
}; const madRobinClockwise: boolean = (findPairOpposite(move.parameters.who, id) !== null) === startPos.which.isOnLeftLookingAcross();
const startAndEndPos: SemanticPosition = {
kind: PositionKind.Circle,
which: startPos.which,
facing: startPos.which.facingAcross(),
}
return combine([{ return combine([{
beats: move.beats, beats: move.beats,
startPosition: startAndEndPos, startPosition: startAndEndPos,
endPosition: startAndEndPos, endPosition: startAndEndPos,
movementPattern: { movementPattern: {
kind: SemanticAnimationKind.DoSiDo, kind: SemanticAnimationKind.DoSiDo,
amount: move.parameters.circling, amount: madRobinClockwise ? move.parameters.circling : -move.parameters.circling,
around: startPos.which.leftRightSide(), around: startPos.which.leftRightSide(),
}, },
}]); }]);
@ -641,6 +655,7 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
minAmount: 360, minAmount: 360,
around, around,
byHand: undefined, byHand: undefined,
close: true,
}, },
}), }),
swing, swing,
@ -684,14 +699,17 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
}); });
case "allemande": case "allemande":
case "allemande orbit":
case "gyre": case "gyre":
const allemandeCircling = move.move === "allemande orbit" ? move.parameters.circling1 : move.parameters.circling;
const byHandOrShoulder = (move.move === "gyre" ? move.parameters.shoulder : move.parameters.hand) ? Hand.Right : Hand.Left;
return handlePairedMove(move.parameters.who, ({ startPos, around, withId }) => { return handlePairedMove(move.parameters.who, ({ startPos, around, withId }) => {
// TODO Not sure if this is right. // TODO Not sure if this is right.
const byHandOrShoulder = (move.move === "allemande" ? move.parameters.hand : move.parameters.shoulder) ? Hand.Right : Hand.Left; const swap = allemandeCircling % 360 === 180;
const swap = move.parameters.circling % 360 === 180; if (!swap && allemandeCircling % 360 !== 0) {
if (!swap && move.parameters.circling % 360 !== 0) {
// TODO Support allemande that's not a swap or no-op. // TODO Support allemande that's not a swap or no-op.
throw "Unsupported allemande circle amount: " + move.parameters.circling; throw "Unsupported allemande circle amount: " + allemandeCircling;
} }
let endPosition: SemanticPosition = startPos; let endPosition: SemanticPosition = startPos;
if (swap) { if (swap) {
@ -706,12 +724,62 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
endPosition, endPosition,
movementPattern: { movementPattern: {
kind: SemanticAnimationKind.RotateAround, kind: SemanticAnimationKind.RotateAround,
minAmount: byHandOrShoulder === Hand.Right ? move.parameters.circling : -move.parameters.circling, minAmount: byHandOrShoulder === Hand.Right ? allemandeCircling : -allemandeCircling,
around, around,
byHand: move.move === "allemande" ? byHandOrShoulder : undefined, byHand: move.move === "allemande" || move.move === "allemande orbit" ? byHandOrShoulder : undefined,
close: true,
}, },
}, },
], startPos); ], startPos);
}, move.move !== "allemande orbit" ? undefined : ({ id, startPos}) => {
const orbitAmount = move.parameters.circling2;
const swap = orbitAmount % 360 === 180;
if (!swap && orbitAmount % 360 !== 0) {
// TODO Support allemande that's not a swap or no-op.
throw "Unsupported allemande orbit amount: " + orbitAmount;
}
const startingPos: SemanticPosition = {
...startPos,
hands: undefined,
balance: undefined,
dancerDistance: undefined,
}
let endPosition: SemanticPosition;
if (swap) {
if (startingPos.kind === PositionKind.Circle) {
endPosition =
{
...startingPos,
which: startingPos.which.swapDiagonal(),
facing: startingPos.which.isLeft() ? Facing.Left : Facing.Right,
}
} else {
endPosition =
{
...startingPos,
which: startingPos.which.swapSides(),
facing: startingPos.which.isLeft() ? Facing.Left : Facing.Right,
}
}
} else {
endPosition = startingPos;
}
return combine([
{
beats: move.beats,
endPosition,
movementPattern: {
kind: SemanticAnimationKind.RotateAround,
// Orbit is opposite direction of allemande.
minAmount: byHandOrShoulder === Hand.Right ? -orbitAmount : +orbitAmount,
around: "Center",
byHand: undefined,
close: false,
},
},
], startingPos);
}); });
case "revolving door": case "revolving door":
@ -738,6 +806,7 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
minAmount: byHand === Hand.Right ? 180 : -180, minAmount: byHand === Hand.Right ? 180 : -180,
around: "Center", around: "Center",
byHand, byHand,
close: false,
}, },
}, },
prevEnd => ({ prevEnd => ({
@ -756,6 +825,7 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
minAmount: byHand === Hand.Right ? 180 : -180, minAmount: byHand === Hand.Right ? 180 : -180,
around: "Center", around: "Center",
byHand, byHand,
close: true,
}, },
}, },
], startPos); ], startPos);
@ -1385,26 +1455,46 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
case "pass through": case "pass through":
if (move.parameters.dir !== "along") { if (move.parameters.dir !== "along") {
throw new Error("Unsupport pass through direction: " + move.parameters.dir); throw new Error("Unsupported pass through direction: " + move.parameters.dir);
} }
const passShoulder = move.parameters.shoulder ? Hand.Right : Hand.Left;
return handleMove(({ startPos }) => { return handleMove(({ startPos }) => {
if (startPos.kind !== PositionKind.ShortLines) { if (startPos.kind === PositionKind.Circle) {
throw new Error("pass through from circle is unsupported"); const facing = startPos.which.facingUpOrDown();
const endPos: SemanticPosition = {
kind: PositionKind.Circle,
which: startPos.which,
facing,
setOffset: (startPos.setOffset ?? 0) + (facing === Facing.Up ? -0.5 : +0.5),
lineOffset: startPos.lineOffset,
};
return combine([{
beats: move.beats,
endPosition: endPos,
movementPattern: {
kind: SemanticAnimationKind.PassBy,
around: startPos.which.leftRightSide(),
side: passShoulder,
withHands: false,
},
}], startPos);
} else {
// TODO This assumes short *wavy* lines.
const endPos: SemanticPosition = {
...startPos,
balance: undefined,
which: startPos.which.swapOnSide(),
setOffset: (startPos.setOffset ?? 0) + (startPos.facing === Facing.Up ? -0.5 : +0.5),
};
return combine([{
beats: move.beats,
endPosition: endPos,
movementPattern: { kind: SemanticAnimationKind.Linear },
}], startPos);
} }
// TODO This assumes short *wavy* lines.
const endPos: SemanticPosition = {
...startPos,
balance: undefined,
which: startPos.which.swapOnSide(),
setOffset: (startPos.setOffset ?? 0) + (startPos.facing === Facing.Up ? -0.5 : +0.5),
};
return combine([{
beats: move.beats,
endPosition: endPos,
movementPattern: { kind: SemanticAnimationKind.Linear },
}], startPos);
}); });
case "hey": case "hey":

View File

@ -139,6 +139,10 @@ export class CirclePosition {
return this.isLeft() ? Facing.Left : Facing.Right; return this.isLeft() ? Facing.Left : Facing.Right;
} }
public facingUpOrDown() : Facing.Up | Facing.Down {
return this.isTop() ? Facing.Down : Facing.Up;
}
public toString() : string { public toString() : string {
return this.enumValue.toString(); return this.enumValue.toString();
} }

View File

@ -72,6 +72,9 @@ export type SemanticAnimation = {
around: CircleSideOrCenter, around: CircleSideOrCenter,
byHand: Hand | undefined, byHand: Hand | undefined,
// If true, move in close while rotating.
close: boolean,
} | { } | {
kind: SemanticAnimationKind.Swing, kind: SemanticAnimationKind.Swing,
@ -545,10 +548,11 @@ export function animateLowLevelMove(move: LowLevelMove): animation.AnimationSegm
width: setWidth / 5, width: setWidth / 5,
height: setHeight / 5, height: setHeight / 5,
}, },
facing: animation.RotationAnimationFacing.Center, closer: { facing: animation.RotationAnimationFacing.Center,
closer: move.movementPattern.close ? {
transitionBeats: 1, transitionBeats: 1,
minDistance: setWidth, minDistance: setWidth,
}, } : undefined,
hands hands
}), }),
flags: { flags: {

View File

@ -520,6 +520,7 @@ function loadDance() {
cancelAnimationFrame(cancelAnim); cancelAnimationFrame(cancelAnim);
playButton.innerText = 'Play'; playButton.innerText = 'Play';
} }
progressionSelector.value = '0';
beatSlider.value = '0'; beatSlider.value = '0';
beatSlider.max = r.animation.numBeats.toString(); beatSlider.max = r.animation.numBeats.toString();
beatDisplay.innerText = '0.0'; beatDisplay.innerText = '0.0';