Skip to content

Commit 0a33357

Browse files
committed
poc: step editor
Just getting things loaded without panics was a bit of a challenge. For now, I'm committing these changes and will complete the actual editor in other commits. In the medium term, I really need to fix how steps and poses are loaded.
1 parent a4ec9c1 commit 0a33357

23 files changed

+614
-110
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<script>
2+
import { LEFT_RIGHT_COLORING_LIGHT } from '$lib/constants';
3+
import { PoseWrapper } from '$lib/instructor/bouncy_instructor';
4+
import Svg from './avatar/Svg.svelte';
5+
import SvgAvatar from './avatar/SvgAvatar.svelte';
6+
7+
/** @type {PoseWrapper} */
8+
export let pose;
9+
export let size = 200;
10+
export let style = LEFT_RIGHT_COLORING_LIGHT;
11+
</script>
12+
13+
<div class="avatar">
14+
<Svg width={size} height={size} orderByZ>
15+
<SvgAvatar skeleton={pose.skeleton()} width={size} height={size} {style}
16+
></SvgAvatar>
17+
</Svg>
18+
</div>
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<script>
2+
import { t } from '$lib/i18n';
3+
import {
4+
PoseWrapper,
5+
StepPositionBuilder,
6+
StepWrapper,
7+
} from '$lib/instructor/bouncy_instructor';
8+
import { getContext } from 'svelte';
9+
import DraggableList from '../ui/DraggableList.svelte';
10+
import UiBox from '../ui/UiBox.svelte';
11+
import Pose from '../Pose.svelte';
12+
13+
const localCollectionCtx = getContext('localCollection');
14+
const availablePoses = localCollectionCtx.poses;
15+
16+
/** @param {StepWrapper} loadedStep */
17+
export function loadStep(loadedStep) {
18+
step = loadedStep;
19+
stepName = step.name;
20+
}
21+
22+
/** @type {StepWrapper} */
23+
let step = newStep();
24+
let stepName = $t('editor.name-input-placeholder');
25+
$: stepPositionBuilders = step.positions();
26+
27+
let showAddNewItem = false;
28+
29+
function newStep() {
30+
const idNum = Math.random().toFixed(6).substring(2);
31+
const id = `step-${idNum}`;
32+
const name = `Step ${idNum} Name`;
33+
const step = new StepWrapper(id, name, 'lab');
34+
localCollectionCtx.addStep(step);
35+
return step;
36+
}
37+
38+
/** @param {PoseWrapper} pose */
39+
function addPose(pose) {
40+
step.addPosition(new StepPositionBuilder(pose));
41+
step = step;
42+
}
43+
</script>
44+
45+
<input id="name" name="name" bind:value={stepName} />
46+
47+
<DraggableList items={stepPositionBuilders} bind:showAddNewItem>
48+
<slot slot="main" let:item={position}>
49+
<div class="pose">
50+
<Pose pose={position.pose()}></Pose>
51+
</div>
52+
</slot>
53+
<slot slot="name" let:item={position}>{position.pose().name('en')}</slot>
54+
</DraggableList>
55+
56+
{#if showAddNewItem}
57+
<UiBox title="editor.pick-pose-prompt">
58+
<div>
59+
{#each $availablePoses as pose}
60+
<div
61+
on:click={() => addPose(pose)}
62+
role="button"
63+
tabindex={0}
64+
on:keydown={(event) => {
65+
if (event.key === 'Enter' || event.key === ' ') {
66+
addPose(pose);
67+
}
68+
}}
69+
>
70+
<div class="pose">
71+
<p>{pose.name('en')}</p>
72+
<Pose {pose}></Pose>
73+
</div>
74+
</div>
75+
{/each}
76+
</div>
77+
</UiBox>
78+
{/if}

bouncy_frontend/src/lib/i18n/de-CH.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,14 @@
8484
"delete-dance-confirmation": "Tanz wirklich löschen?",
8585
"edit-button": "Tanz bearbeiten",
8686
"edit-copy-button": "Kopieren und bearbeiten",
87+
"pick-pose-prompt": "Wähle eine Pose",
8788
"pick-step-prompt": "Wähle einen Schritt",
8889
"saving-prompt": "Wie soll der Tanz gespeichert werden?",
8990
"save-copy-button": "Kopie speichern",
9091
"overwrite-existing-button": "Überschreiben",
9192
"direction": "Richtung",
9293
"speed": "Tempo",
94+
"name-input-placeholder": "Name",
9395
"pose": {
9496
"title": "Labor: Posen",
9597
"list": "Meine Posen",

bouncy_frontend/src/lib/i18n/en-GB.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,14 @@
8484
"delete-dance-confirmation": "Delete the dance?",
8585
"edit-button": "Edit dance",
8686
"edit-copy-button": "Copy and edit",
87+
"pick-pose-prompt": "Pick a pose",
8788
"pick-step-prompt": "Pick a step",
8889
"saving-prompt": "How to save the dance?",
8990
"save-copy-button": "Save a copy",
9091
"overwrite-existing-button": "Overwrite",
9192
"direction": "Direction",
9293
"speed": "Speed",
94+
"name-input-placeholder": "Name",
9395
"pose": {
9496
"title": "Lab: Poses",
9597
"list": "My poses",

bouncy_frontend/src/lib/instructor/bouncy_instructor.d.ts

Lines changed: 104 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -74,30 +74,13 @@ export function dances(): (DanceWrapper)[];
7474
*/
7575
export function danceBuilderFromDance(dance_id: string): DanceBuilder;
7676
/**
77+
* @param {(PoseWrapper)[]} poses
7778
*/
78-
export enum DetectionState {
79-
/**
80-
* Neutral state, not detecting anything.
81-
*/
82-
Init = 1,
79+
export function addLocalPoses(poses: (PoseWrapper)[]): void;
8380
/**
84-
* Dance is positioning themselves, detecting the idle position.
81+
* @param {(StepWrapper)[]} steps
8582
*/
86-
Positioning = 2,
87-
/**
88-
* About to go over to live tracking, playing a countdown audio.
89-
*/
90-
CountDown = 3,
91-
/**
92-
* Tracking current movements.
93-
*/
94-
LiveTracking = 4,
95-
/**
96-
* No longer tracking but the results of the previous tracking are
97-
* available.
98-
*/
99-
TrackingDone = 5,
100-
}
83+
export function loadLocalSteps(steps: (StepWrapper)[]): void;
10184
/**
10285
*/
10386
export enum DetectionFailureReason {
@@ -149,6 +132,31 @@ export enum PoseHint {
149132
ZOrder = 2,
150133
WrongDirection = 3,
151134
}
135+
/**
136+
*/
137+
export enum DetectionState {
138+
/**
139+
* Neutral state, not detecting anything.
140+
*/
141+
Init = 1,
142+
/**
143+
* Dance is positioning themselves, detecting the idle position.
144+
*/
145+
Positioning = 2,
146+
/**
147+
* About to go over to live tracking, playing a countdown audio.
148+
*/
149+
CountDown = 3,
150+
/**
151+
* Tracking current movements.
152+
*/
153+
LiveTracking = 4,
154+
/**
155+
* No longer tracking but the results of the previous tracking are
156+
* available.
157+
*/
158+
TrackingDone = 5,
159+
}
152160

153161
import type { Readable } from "svelte/store";
154162

@@ -745,6 +753,17 @@ export class Segment {
745753
export class Skeleton {
746754
free(): void;
747755
/**
756+
* Compute 2d coordinates for the skeleton for rendering.
757+
*
758+
* The skeleton will be rendered assuming hard-coded values for body part
759+
* proportional lengths, multiplied with the size parameter. The hip
760+
* segment will have its center at the given position.
761+
* @param {Cartesian2d} hip_center
762+
* @param {number} size
763+
* @returns {SkeletonV2}
764+
*/
765+
render(hip_center: Cartesian2d, size: number): SkeletonV2;
766+
/**
748767
* @param {boolean} sideway
749768
* @returns {Skeleton}
750769
*/
@@ -758,17 +777,6 @@ export class Skeleton {
758777
*/
759778
debugString(): string;
760779
/**
761-
* Compute 2d coordinates for the skeleton for rendering.
762-
*
763-
* The skeleton will be rendered assuming hard-coded values for body part
764-
* proportional lengths, multiplied with the size parameter. The hip
765-
* segment will have its center at the given position.
766-
* @param {Cartesian2d} hip_center
767-
* @param {number} size
768-
* @returns {SkeletonV2}
769-
*/
770-
render(hip_center: Cartesian2d, size: number): SkeletonV2;
771-
/**
772780
* Does the dancer face away more than they face the camera?
773781
*/
774782
backwards: boolean;
@@ -902,6 +910,10 @@ export class StepFileWrapper {
902910
*/
903911
constructor();
904912
/**
913+
* FIXME: This adds steps as lab steps and then calls a warm up. This is to
914+
* avoid the problem where a step wrapper can only be created for steps
915+
* that are already registered in global state. A proper refactoring should
916+
* solve this.
905917
* @param {string} text
906918
* @returns {StepFileWrapper}
907919
*/
@@ -928,10 +940,34 @@ export class StepFileWrapper {
928940
buildRon(): string;
929941
}
930942
/**
943+
* Used in the editor to add and edit poses of a step.
944+
*/
945+
export class StepPositionBuilder {
946+
free(): void;
947+
/**
948+
* @param {PoseWrapper} pose
949+
*/
950+
constructor(pose: PoseWrapper);
951+
/**
952+
* @returns {PoseWrapper}
953+
*/
954+
pose(): PoseWrapper;
955+
/**
956+
* @param {number} height
957+
*/
958+
setJumpHeight(height: number): void;
959+
}
960+
/**
931961
*/
932962
export class StepWrapper {
933963
free(): void;
934964
/**
965+
* @param {string} id
966+
* @param {string} name
967+
* @param {string} source
968+
*/
969+
constructor(id: string, name: string, source: string);
970+
/**
935971
* @param {number} beat
936972
* @returns {Skeleton}
937973
*/
@@ -955,6 +991,33 @@ export class StepWrapper {
955991
*/
956992
jumpHeight(beat: number): number | undefined;
957993
/**
994+
* Look up poses from the global collection, do not use for courses that
995+
* require a custom collection.
996+
* @returns {(PoseWrapper)[]}
997+
*/
998+
poses(): (PoseWrapper)[];
999+
/**
1000+
* Positions with poses from the global collection, do not use for courses
1001+
* that require a custom collection.
1002+
* @returns {(StepPositionBuilder)[]}
1003+
*/
1004+
positions(): (StepPositionBuilder)[];
1005+
/**
1006+
* Add poses from the global collection, do not use for courses that
1007+
* require a custom collection.
1008+
* @param {StepPositionBuilder} position
1009+
*/
1010+
addPosition(position: StepPositionBuilder): void;
1011+
/**
1012+
* @param {number} index
1013+
*/
1014+
removePosition(index: number): void;
1015+
/**
1016+
* @param {number} index
1017+
* @param {StepPositionBuilder} position
1018+
*/
1019+
insertPosition(index: number, position: StepPositionBuilder): void;
1020+
/**
9581021
* The number of beats the step takes for one repetition.
9591022
*/
9601023
readonly beats: number;
@@ -983,15 +1046,6 @@ export class StepWrapper {
9831046
export class Tracker {
9841047
free(): void;
9851048
/**
986-
* @param {number} timestamp
987-
* @returns {ExportedFrame}
988-
*/
989-
exportFrame(timestamp: number): ExportedFrame;
990-
/**
991-
* @returns {string}
992-
*/
993-
exportKeypoints(): string;
994-
/**
9951049
* Create a tracker for all known steps.
9961050
*/
9971051
constructor();
@@ -1150,6 +1204,15 @@ export class Tracker {
11501204
*/
11511205
renderedKeypointsAt(timestamp: number, width: number, height: number): SkeletonV2 | undefined;
11521206
/**
1207+
* @param {number} timestamp
1208+
* @returns {ExportedFrame}
1209+
*/
1210+
exportFrame(timestamp: number): ExportedFrame;
1211+
/**
1212+
* @returns {string}
1213+
*/
1214+
exportKeypoints(): string;
1215+
/**
11531216
*/
11541217
readonly detectionState: ReadableDetectionState;
11551218
/**

bouncy_frontend/src/lib/instructor/bouncy_instructor_bg.wasm.d.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint-disable */
22
export const memory: WebAssembly.Memory;
33
export const __wbindgen_export_2: WebAssembly.Table;
4+
export function addLocalPoses(a: number, b: number): void;
45
export function audioeffect_soundId(a: number, b: number): void;
56
export function cartesian2d_add(a: number, b: number): number;
67
export function cartesian2d_new(a: number, b: number): number;
@@ -62,6 +63,7 @@ export function limberror_name(a: number, b: number): void;
6263
export function limberror_render(a: number, b: number, c: number): void;
6364
export function loadDanceFile(a: number, b: number): number;
6465
export function loadDanceString(a: number, b: number, c: number): void;
66+
export function loadLocalSteps(a: number, b: number): void;
6567
export function loadPoseFile(a: number, b: number): number;
6668
export function loadPoseString(a: number, b: number, c: number): void;
6769
export function loadStepFile(a: number, b: number, c: number, d: number): number;
@@ -106,14 +108,23 @@ export function stepfilewrapper_new_empty(): number;
106108
export function stepfilewrapper_overwriteStep(a: number, b: number, c: number): void;
107109
export function stepfilewrapper_removeStep(a: number, b: number, c: number, d: number): void;
108110
export function stepfilewrapper_steps(a: number, b: number): void;
111+
export function steppositionbuilder_new(a: number): number;
112+
export function steppositionbuilder_pose(a: number): number;
113+
export function steppositionbuilder_setJumpHeight(a: number, b: number): void;
109114
export function steps(a: number): void;
110115
export function stepsByName(a: number, b: number, c: number): void;
111116
export function stepsBySource(a: number, b: number, c: number): void;
117+
export function stepwrapper_addPosition(a: number, b: number): void;
112118
export function stepwrapper_beats(a: number): number;
113119
export function stepwrapper_bodyShift(a: number, b: number): number;
114120
export function stepwrapper_id(a: number, b: number): void;
121+
export function stepwrapper_insertPosition(a: number, b: number, c: number, d: number): void;
115122
export function stepwrapper_jumpHeight(a: number, b: number, c: number): void;
116123
export function stepwrapper_name(a: number, b: number): void;
124+
export function stepwrapper_new_empty(a: number, b: number, c: number, d: number, e: number, f: number): number;
125+
export function stepwrapper_poses(a: number, b: number): void;
126+
export function stepwrapper_positions(a: number, b: number): void;
127+
export function stepwrapper_removePosition(a: number, b: number, c: number): void;
117128
export function stepwrapper_rotatedSkeleton(a: number, b: number, c: number): number;
118129
export function stepwrapper_skeleton(a: number, b: number): number;
119130
export function stepwrapper_variation(a: number, b: number): void;
@@ -299,6 +310,7 @@ export function __wbg_skeletonsidev2_free(a: number, b: number): void;
299310
export function __wbg_skeletonv2_free(a: number, b: number): void;
300311
export function __wbg_skeletonwrapper_free(a: number, b: number): void;
301312
export function __wbg_stepfilewrapper_free(a: number, b: number): void;
313+
export function __wbg_steppositionbuilder_free(a: number, b: number): void;
302314
export function __wbg_stepwrapper_free(a: number, b: number): void;
303315
export function __wbg_tracker_free(a: number, b: number): void;
304316
export function __wbg_zerror_free(a: number, b: number): void;

0 commit comments

Comments
 (0)