Compare commits

...

2 Commits

2 changed files with 109 additions and 25 deletions

View File

@ -991,7 +991,11 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
endSet += startPos.which.isLeft() ? +1 : -1; endSet += startPos.which.isLeft() ? +1 : -1;
break; break;
} }
const startPosition = { ...startPos, hands: new Map<Hand, HandConnection>([[hand, { hand, to }]]) }; const startPosition = {
...startPos,
hands: new Map<Hand, HandConnection>([[hand, { hand, to }]]),
facing: startPos.which.facingAcross(),
};
const turnTo = hand === Hand.Right ? HandTo.DancerRight : HandTo.DancerLeft; const turnTo = hand === Hand.Right ? HandTo.DancerRight : HandTo.DancerLeft;
@ -1030,10 +1034,11 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
}) })
], startPosition); ], startPosition);
} else { } else {
const startingPos = { ...startPos, facing: startPos.which.facingAcross() };
return combine([ return combine([
{ {
beats: pullBeats, beats: pullBeats,
endPosition: startPos, endPosition: startingPos,
movementPattern: { movementPattern: {
kind: SemanticAnimationKind.StandStill, kind: SemanticAnimationKind.StandStill,
} }
@ -1041,7 +1046,7 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
{ {
beats: turnBeats, beats: turnBeats,
endPosition: { endPosition: {
...startPos, ...startingPos,
// TODO Does CourtesyTurn always end in same position? // TODO Does CourtesyTurn always end in same position?
which: startPos.which, which: startPos.which,
}, },
@ -1049,7 +1054,7 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
kind: SemanticAnimationKind.CourtesyTurn, kind: SemanticAnimationKind.CourtesyTurn,
} }
} }
], startPos); ], startingPos);
} }
}); });
@ -1426,17 +1431,22 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
const centerShoulder = firstPassInCenter === move.parameters.shoulder ? Hand.Right : Hand.Left; const centerShoulder = firstPassInCenter === move.parameters.shoulder ? Hand.Right : Hand.Left;
const endsShoulder = centerShoulder.opposite(); const endsShoulder = centerShoulder.opposite();
return handleMove(({ id, startPos }) => { return handleMove(({ id, startPos }) => {
const endsInCircle = startPos.kind === PositionKind.Circle;
type HeyStep = { type HeyStep = {
kind: "Loop" | "CenterPass" | "EndsPass", kind: "StandStill" | "Loop" | "CenterPass" | "EndsPassIn" | "EndsPassOut",
endPosition: SemanticPosition, endPosition: SemanticPosition,
} }
function heyStepToPartialLowLevelMove(heyStep: HeyStep): PartialLowLevelMove & { heyStep: HeyStep } { function heyStepToPartialLowLevelMove(heyStep: HeyStep): PartialLowLevelMove & { heyStep: HeyStep } {
return { return {
beats: heyPartBeats, beats: heyPartBeats,
// TODO use circle positions on ends? ... unless hey ends in a box the gnat or similar...
endPosition: heyStep.endPosition, endPosition: heyStep.endPosition,
movementPattern: heyStep.kind === "Loop" ? { movementPattern: heyStep.kind === "StandStill" ? {
kind: SemanticAnimationKind.StandStill,
} : heyStep.kind === "Loop" ? {
// TODO Loop should probably be its own kind? Or RotateAround? // TODO Loop should probably be its own kind? Or RotateAround?
kind: SemanticAnimationKind.Linear, kind: SemanticAnimationKind.Linear,
minRotation: endsShoulder === Hand.Right ? +180 : -180,
} : { } : {
kind: SemanticAnimationKind.PassBy, kind: SemanticAnimationKind.PassBy,
around: heyStep.kind === "CenterPass" ? "Center" : heyStep.endPosition.which.leftRightSide(), around: heyStep.kind === "CenterPass" ? "Center" : heyStep.endPosition.which.leftRightSide(),
@ -1446,31 +1456,73 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
heyStep, heyStep,
}; };
} }
function continueHey(prevStep: HeyStep, isLast: boolean): HeyStep { function continueHey(prevStep: HeyStep, stepsLeft: number): HeyStep {
// Continuing hey so everyone is either passing (in center or on ends) or looping on ends. // Continuing hey so everyone is either passing (in center or on ends) or looping on ends.
if (prevStep.endPosition.kind === PositionKind.Circle) { if (prevStep.endPosition.kind === PositionKind.Circle) {
// Hasn't started hey yet, passing on ends to enter hey. if (prevStep.endPosition.facing === prevStep.endPosition.which.facingAcross()) {
return { if (stepsLeft === 0) {
kind: "EndsPass", return {
endPosition: { kind: "StandStill",
kind: PositionKind.ShortLines, endPosition: prevStep.endPosition,
which: prevStep.endPosition.which.isLeft() ? ShortLinesPosition.MiddleLeft : ShortLinesPosition.MiddleRight, }
facing: prevStep.endPosition.which.facingAcross(), }
setOffset: prevStep.endPosition.setOffset, return {
lineOffset: prevStep.endPosition.lineOffset, kind: "EndsPassIn",
}, endPosition: {
kind: PositionKind.ShortLines,
which: prevStep.endPosition.which.isLeft() ? ShortLinesPosition.MiddleLeft : ShortLinesPosition.MiddleRight,
facing: prevStep.endPosition.which.facingAcross(),
setOffset: prevStep.endPosition.setOffset,
lineOffset: prevStep.endPosition.lineOffset,
},
}
}
else {
if (stepsLeft === 1 && !endsInCircle) {
return {
kind: "Loop",
endPosition: {
kind: PositionKind.ShortLines,
which: prevStep.endPosition.which.isLeft() ? ShortLinesPosition.FarLeft : ShortLinesPosition.FarRight,
facing: prevStep.endPosition.which.facingAcross(),
setOffset: prevStep.endPosition.setOffset,
lineOffset: prevStep.endPosition.lineOffset,
},
}
}
return {
kind: "Loop",
endPosition: {
...prevStep.endPosition,
which: prevStep.endPosition.which.swapUpAndDown(),
facing: prevStep.endPosition.which.facingAcross()
},
}
} }
} }
else if (prevStep.endPosition.kind === PositionKind.ShortLines) { else if (prevStep.endPosition.kind === PositionKind.ShortLines) {
const isFacingSide = prevStep.endPosition.facing === prevStep.endPosition.which.facingSide(); const isFacingSide = prevStep.endPosition.facing === prevStep.endPosition.which.facingSide();
if (!prevStep.endPosition.which.isMiddle() && !isFacingSide) { const inMiddle = prevStep.endPosition.which.isMiddle();
if (!inMiddle && !isFacingSide) {
return { return {
kind: "Loop", kind: "Loop",
endPosition: { ...prevStep.endPosition, facing: prevStep.endPosition.which.facingSide() }, endPosition: { ...prevStep.endPosition, facing: prevStep.endPosition.which.facingSide() },
} }
} else { } else if (inMiddle && isFacingSide) {
return { return {
kind: isFacingSide ? "EndsPass" : "CenterPass", kind: "EndsPassOut",
endPosition: {
...prevStep.endPosition,
kind: PositionKind.Circle,
which: prevStep.endPosition.which.isLeft()
? (endsShoulder === Hand.Right ? CirclePosition.TopLeft : CirclePosition.BottomLeft)
: (endsShoulder === Hand.Right ? CirclePosition.BottomRight : CirclePosition.TopRight),
},
}
}
else {
return {
kind: isFacingSide ? (inMiddle ? "EndsPassOut" : "EndsPassIn") : "CenterPass",
endPosition: { endPosition: {
...prevStep.endPosition, ...prevStep.endPosition,
which: isFacingSide ? prevStep.endPosition.which.swapOnSide() : prevStep.endPosition.which.swapSides() which: isFacingSide ? prevStep.endPosition.which.swapOnSide() : prevStep.endPosition.which.swapSides()
@ -1485,18 +1537,49 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
let firstHeyStep: HeyStep; let firstHeyStep: HeyStep;
let startingPos: SemanticPosition; let startingPos: SemanticPosition;
if (firstPassInCenter) { if (firstPassInCenter) {
if (startPos.kind !== PositionKind.Circle) {
throw new Error("Hey starting in center not from circle is unsupported.");
}
const inCenterFirst = findPairOpposite(move.parameters.who, id) !== null; const inCenterFirst = findPairOpposite(move.parameters.who, id) !== null;
// TODO This is probably the most common kind of hey, definitely top priority. startingPos = {
throw new Error("Hey starting passing in center is unsupported."); kind: startPos.kind,
which: startPos.which,
facing: startPos.which.isLeft() ? Facing.Right : Facing.Left,
setOffset: startPos.setOffset,
lineOffset: startPos.lineOffset,
};
if (inCenterFirst) {
firstHeyStep = {
kind: "CenterPass",
endPosition: {
kind: PositionKind.ShortLines,
which: startPos.which.isLeft() ? ShortLinesPosition.MiddleRight : ShortLinesPosition.MiddleLeft,
facing: startingPos.facing,
setOffset: startPos.setOffset,
lineOffset: startPos.lineOffset,
}
};
} else {
firstHeyStep = {
kind: "StandStill",
endPosition: startingPos,
}
}
} else { } else {
if (startPos.kind !== PositionKind.ShortLines) { if (startPos.kind !== PositionKind.ShortLines) {
throw new Error("Hey with first pass on ends must start approximately in short lines."); throw new Error("Hey with first pass on ends must start approximately in short lines.");
} }
const startFacing = startPos.which.facingSide(); const startFacing = startPos.which.facingSide();
startingPos = { ...startPos, facing: startFacing, hands: undefined }; startingPos = {
kind: startPos.kind,
which: startPos.which,
facing: startFacing,
setOffset: startPos.setOffset,
lineOffset: startPos.lineOffset,
};
firstHeyStep = { firstHeyStep = {
kind: "EndsPass", kind: startingPos.which.isMiddle() ? "EndsPassOut" : "EndsPassIn",
endPosition: { ...startingPos, which: startPos.which.swapOnSide() }, endPosition: { ...startingPos, which: startPos.which.swapOnSide() },
} }
} }
@ -1504,7 +1587,7 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
const heySteps: HeyStep[] = [firstHeyStep]; const heySteps: HeyStep[] = [firstHeyStep];
for(let i = 1; i < heyParts; i++) { for(let i = 1; i < heyParts; i++) {
const isLast = i === heyParts - 1; const isLast = i === heyParts - 1;
const nextHeyStep = continueHey(heySteps[i - 1], isLast); const nextHeyStep = continueHey(heySteps[i - 1], heyParts - i - 1);
heySteps.push(nextHeyStep); heySteps.push(nextHeyStep);
} }
return combine(heySteps.map(heyStepToPartialLowLevelMove), { ...startingPos, hands: undefined }); return combine(heySteps.map(heyStepToPartialLowLevelMove), { ...startingPos, hands: undefined });

View File

@ -92,6 +92,7 @@ updateCanvasSettings({});
const bpmSelector = document.createElement('input'); const bpmSelector = document.createElement('input');
bpmSelector.type = 'number'; bpmSelector.type = 'number';
bpmSelector.value = '180'; bpmSelector.value = '180';
bpmSelector.step = '20';
bpmSelector.id = 'bpm'; bpmSelector.id = 'bpm';
bpmSelector.style.width = '4em'; bpmSelector.style.width = '4em';
const bpmLabel = document.createElement('label'); const bpmLabel = document.createElement('label');