Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b673dbc
Added toe entries.
Sebane1 Oct 8, 2025
26bd352
Add toe handling to GUI
Sebane1 Oct 9, 2025
5409c48
Add formatting.
Sebane1 Oct 9, 2025
329d559
Properly reference toe trackers.
Sebane1 Oct 9, 2025
777a21d
Add toesOSCHandler, and add it to VRServer
Sebane1 Oct 11, 2025
08bdee7
Ensure correct config is passed in. Using config from VrcOscHandler
Sebane1 Oct 11, 2025
97d1cd2
Actually requests updates to happen. Fix an issue with axis and inver…
Sebane1 Oct 11, 2025
b13ef57
Switch from computed trackers to bones for rotation.
Sebane1 Oct 11, 2025
6245cb3
Fix manual mounting menu for toe entries.
Sebane1 Oct 12, 2025
a74b704
Both feet behave the same now, but math not quite mathing.
Sebane1 Oct 12, 2025
c10a242
Add offset for pitch angle.
Sebane1 Oct 13, 2025
aec64d9
Name Refactor, and correct math that doesnt make sense.
Sebane1 Oct 21, 2025
d9856a5
Add toe UI entry
Sebane1 Oct 21, 2025
b1e67ac
Add toe parameter to UI, update flatbuffers.
Sebane1 Oct 21, 2025
66dc9e4
Refactor datatypes and variables for toes to match toe muscle naming.
Sebane1 Oct 21, 2025
1c0f083
Add missing tracker roles
Sebane1 Oct 21, 2025
edf6ad8
Fix naming assignments for assigning body parts to trackers.
Sebane1 Oct 22, 2025
8e9c310
Update translations to include toes.
Sebane1 Oct 22, 2025
c34f3b1
Add translation for general toes.
Sebane1 Oct 22, 2025
d516c15
Get tracker assignment working. Basic skeleton rendering for toes.
Sebane1 Oct 22, 2025
eebcac4
Find decent enough offsets for displaying toes.
Sebane1 Oct 22, 2025
0fea6a2
I dont think we actually need to null check these. Next function reli…
Sebane1 Oct 22, 2025
ac7a0e9
Remove X axis offset from toes, it interfered with other calculations.
Sebane1 Oct 22, 2025
e9c58d7
Remove 90 degree offset for OSC calculation. It is no longer needed a…
Sebane1 Oct 22, 2025
07bb0a3
Remove debug console logging from GUI
Sebane1 Oct 24, 2025
f9a42aa
Adjust syntax used in RelaxedPose.kt
Sebane1 Oct 24, 2025
2e1c531
Condense redundant rendering logic for feet/toes
Sebane1 Nov 1, 2025
a9f7150
Fix an issue where pinky toe was not getting full reset.
Sebane1 Nov 6, 2025
4f15682
Added toe splay.
Sebane1 Nov 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion gui/public/i18n/en/translation.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,15 @@ body_part-RIGHT_RING_INTERMEDIATE = Right ring intermediate
body_part-RIGHT_RING_DISTAL = Right ring distal
body_part-RIGHT_LITTLE_PROXIMAL = Right little proximal
body_part-RIGHT_LITTLE_INTERMEDIATE = Right little intermediate
body_part-RIGHT_LITTLE_DISTAL = Right little distal
body_part-RIGHT_LITTLE_DISTAL = Right little
body_part-LEFT_TOES = Left Toes
body_part-LEFT_TOES_ABDUCTOR_HALLUCIS = Left Big Toe
body_part-LEFT_TOES_DIGITORUM_BREVIS = Left Middle Toes
body_part-LEFT_TOES_ABDUCTOR_DIGITI_MINIMI = Left Pinky
body_part-RIGHT_TOES = Right Toes
body_part-RIGHT_TOES_ABDUCTOR_HALLUCIS = Right Big Toe
body_part-RIGHT_TOES_DIGITORUM_BREVIS = Right Middle Toes
body_part-RIGHT_TOES_ABDUCTOR_DIGITI_MINIMI = Right Pinky

## BoardType
board_type-UNKNOWN = Unknown
Expand Down Expand Up @@ -803,6 +811,7 @@ settings-osc-vrchat-network-trackers-hip = Hip
settings-osc-vrchat-network-trackers-knees = Knees
settings-osc-vrchat-network-trackers-feet = Feet
settings-osc-vrchat-network-trackers-elbows = Elbows
settings-osc-vrchat-network-trackers-toes = Toes

## VMC OSC settings
settings-osc-vmc = Virtual Motion Capture
Expand Down
34 changes: 22 additions & 12 deletions gui/src/components/commons/BodyPartIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,7 @@ export const mapPart: Record<
[BodyPart.HIP]: ({ width }) => <HipIcon width={width}></HipIcon>,
[BodyPart.LEFT_HIP]: ({ width }) => <HipIcon width={width}></HipIcon>, // Unused
[BodyPart.RIGHT_HIP]: ({ width }) => <HipIcon width={width}></HipIcon>, // Unused
[BodyPart.LEFT_FOOT]: ({ width, currentLocales }) =>
currentLocales.includes('en-x-owo') ? (
<PawIcon></PawIcon>
) : (
<FootIcon width={width}></FootIcon>
),
[BodyPart.LEFT_FOOT]: renderFootLeft,
[BodyPart.LEFT_HAND]: ({ width }) => (
<ControllerIcon width={width}></ControllerIcon>
),
Expand All @@ -62,12 +57,7 @@ export const mapPart: Record<
),
[BodyPart.NECK]: ({ width }) => <NeckIcon width={width}></NeckIcon>,
[BodyPart.NONE]: ({ width }) => <SlimeVRIcon width={width}></SlimeVRIcon>,
[BodyPart.RIGHT_FOOT]: ({ width, currentLocales }) =>
currentLocales.includes('en-x-owo') ? (
<PawIcon></PawIcon>
) : (
<FootIcon width={width} flipped></FootIcon>
),
[BodyPart.RIGHT_FOOT]: renderFootRight,
[BodyPart.RIGHT_HAND]: ({ width }) => (
<ControllerIcon width={width} flipped></ControllerIcon>
),
Expand Down Expand Up @@ -177,8 +167,28 @@ export const mapPart: Record<
[BodyPart.RIGHT_LITTLE_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_TOES_ABDUCTOR_HALLUCIS]: renderFootLeft,
[BodyPart.LEFT_TOES_DIGITORUM_BREVIS]: renderFootLeft,
[BodyPart.LEFT_TOES_ABDUCTOR_DIGITI_MINIMI]: renderFootLeft,
[BodyPart.RIGHT_TOES_ABDUCTOR_HALLUCIS]: renderFootRight,
[BodyPart.RIGHT_TOES_DIGITORUM_BREVIS]: renderFootRight,
[BodyPart.RIGHT_TOES_ABDUCTOR_DIGITI_MINIMI]: renderFootRight,
};

function renderFootLeft({ width, currentLocales }) {
if (currentLocales.includes('en-x-owo')) {
return <PawIcon />;
}
return <FootIcon width={width} />;
}

function renderFootRight({ width, currentLocales }) {
if (currentLocales.includes('en-x-owo')) {
return <PawIcon />;
}
return <FootIcon width={width} flipped />;
}

export function BodyPartIcon({
bodyPart = BodyPart.NONE,
width = 24,
Expand Down
56 changes: 56 additions & 0 deletions gui/src/components/commons/PersonFrontIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ export const SIDES = [
upperLeg: BodyPart.LEFT_UPPER_LEG,
lowerLeg: BodyPart.LEFT_LOWER_LEG,
foot: BodyPart.LEFT_FOOT,
toesAbductorHallucis: BodyPart.LEFT_TOES_ABDUCTOR_HALLUCIS,
toesDigitorumBrevis: BodyPart.LEFT_TOES_DIGITORUM_BREVIS,
toesAbductorDigitiMinimi: BodyPart.LEFT_TOES_ABDUCTOR_DIGITI_MINIMI,
},
{
shoulder: BodyPart.RIGHT_SHOULDER,
Expand All @@ -18,6 +21,9 @@ export const SIDES = [
upperLeg: BodyPart.RIGHT_UPPER_LEG,
lowerLeg: BodyPart.RIGHT_LOWER_LEG,
foot: BodyPart.RIGHT_FOOT,
toesAbductorHallucis: BodyPart.RIGHT_TOES_ABDUCTOR_HALLUCIS,
toesDigitorumBrevis: BodyPart.RIGHT_TOES_DIGITORUM_BREVIS,
toesAbductorDigitiMinimi: BodyPart.RIGHT_TOES_ABDUCTOR_DIGITI_MINIMI,
},
];

Expand Down Expand Up @@ -136,6 +142,28 @@ export function PersonFrontIcon({
id={BodyPart[SIDES[right].foot]}
/>

<circle
className="body-part-circle"
cx="90"
cy="395"
r={CIRCLE_RADIUS}
id={BodyPart[SIDES[right].toesAbductorHallucis]}
/>
<circle
className="body-part-circle"
cx="102"
cy="395"
r={CIRCLE_RADIUS}
id={BodyPart[SIDES[right].toesDigitorumBrevis]}
/>
<circle
className="body-part-circle"
cx="114"
cy="395"
r={CIRCLE_RADIUS}
id={BodyPart[SIDES[right].toesAbductorDigitiMinimi]}
/>

<circle
className="body-part-circle"
cx="36"
Expand Down Expand Up @@ -187,6 +215,34 @@ export function PersonFrontIcon({
r={CIRCLE_RADIUS}
id={BodyPart[SIDES[left].foot]}
/>
<circle
className="body-part-circle"
cx="75"
cy="410"
r={CIRCLE_RADIUS}
id="left-toes"
/>
<circle
className="body-part-circle"
cx="75"
cy="395"
r={CIRCLE_RADIUS}
id={BodyPart[SIDES[left].toesAbductorHallucis]}
/>
<circle
className="body-part-circle"
cx="62"
cy="395"
r={CIRCLE_RADIUS}
id={BodyPart[SIDES[left].toesDigitorumBrevis]}
/>
<circle
className="body-part-circle"
cx="50"
cy="395"
r={CIRCLE_RADIUS}
id={BodyPart[SIDES[left].toesAbductorDigitiMinimi]}
/>
</svg>
);
}
83 changes: 83 additions & 0 deletions gui/src/components/onboarding/BodyAssignment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,21 @@ export const LEGS_PARTS = new Set([
BodyPart.LEFT_LOWER_LEG,
BodyPart.RIGHT_LOWER_LEG,
]);

export const TOES_PARTS = new Set([
BodyPart.LEFT_TOES_ABDUCTOR_HALLUCIS,
BodyPart.RIGHT_TOES_ABDUCTOR_HALLUCIS,
BodyPart.LEFT_TOES_DIGITORUM_BREVIS,
BodyPart.RIGHT_TOES_DIGITORUM_BREVIS,
BodyPart.LEFT_TOES_ABDUCTOR_DIGITI_MINIMI,
BodyPart.RIGHT_TOES_ABDUCTOR_DIGITI_MINIMI,
]);

export const LOWER_BODY = new Set([
BodyPart.LEFT_FOOT,
BodyPart.RIGHT_FOOT,
...LEGS_PARTS,
...TOES_PARTS,
]);
export const SPINE_PARTS = [
BodyPart.UPPER_CHEST,
Expand All @@ -34,6 +45,14 @@ export const SPINE_PARTS = [
export const ASSIGNMENT_RULES: Partial<
Record<BodyPart, (BodyPart | BodyPart[])[]>
> = {
[BodyPart.LEFT_TOES_ABDUCTOR_HALLUCIS]: [BodyPart.LEFT_FOOT],
[BodyPart.LEFT_TOES_DIGITORUM_BREVIS]: [BodyPart.LEFT_FOOT],
[BodyPart.LEFT_TOES_ABDUCTOR_DIGITI_MINIMI]: [BodyPart.LEFT_FOOT],

[BodyPart.RIGHT_TOES_ABDUCTOR_HALLUCIS]: [BodyPart.RIGHT_FOOT],
[BodyPart.RIGHT_TOES_DIGITORUM_BREVIS]: [BodyPart.RIGHT_FOOT],
[BodyPart.RIGHT_TOES_ABDUCTOR_DIGITI_MINIMI]: [BodyPart.RIGHT_FOOT],

[BodyPart.LEFT_FOOT]: [
BodyPart.LEFT_LOWER_LEG,
BodyPart.LEFT_UPPER_LEG,
Expand Down Expand Up @@ -90,6 +109,7 @@ export const ASSIGNMENT_MODES: Record<AssignMode, BodyPart[]> = {
...SPINE_PARTS,
...ARMS_PARTS,
...LEGS_PARTS,
...TOES_PARTS,
],
};

Expand Down Expand Up @@ -150,6 +170,7 @@ export function BodyAssignment({
[assignMode]
);


return (
<>
<BodyInteractions
Expand Down Expand Up @@ -263,6 +284,37 @@ export function BodyAssignment({
direction="right"
/>
)}
{hasBodyPart(SIDES[left].toesAbductorHallucis) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[left].toesAbductorHallucis]?.label}
td={trackerPartGrouped[SIDES[left].toesAbductorHallucis]}
role={SIDES[left].toesAbductorHallucis}
onClick={() => onRoleSelected(SIDES[left].toesAbductorHallucis)}
direction="right"
/>
)}
{hasBodyPart(SIDES[left].toesDigitorumBrevis) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[left].toesDigitorumBrevis]?.label}
td={trackerPartGrouped[SIDES[left].toesDigitorumBrevis]}
role={SIDES[left].toesDigitorumBrevis}
onClick={() => onRoleSelected(SIDES[left].toesDigitorumBrevis)}
direction="right"
/>
)}
{hasBodyPart(SIDES[left].toesAbductorDigitiMinimi) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[left].toesAbductorDigitiMinimi]?.label}
td={trackerPartGrouped[SIDES[left].toesAbductorDigitiMinimi]}
role={SIDES[left].toesAbductorDigitiMinimi}
onClick={() => onRoleSelected(SIDES[left].toesAbductorDigitiMinimi)}
direction="right"
/>
)}

</div>
</div>
}
Expand Down Expand Up @@ -392,6 +444,37 @@ export function BodyAssignment({
direction="left"
/>
)}
{hasBodyPart(SIDES[right].toesAbductorHallucis) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[right].toesAbductorHallucis]?.label}
td={trackerPartGrouped[SIDES[right].toesAbductorHallucis]}
role={SIDES[right].toesAbductorHallucis}
onClick={() => onRoleSelected(SIDES[right].toesAbductorHallucis)}
direction="left"
/>
)}
{hasBodyPart(SIDES[right].toesDigitorumBrevis) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[right].toesDigitorumBrevis]?.label}
td={trackerPartGrouped[SIDES[right].toesDigitorumBrevis]}
role={SIDES[right].toesDigitorumBrevis}
onClick={() => onRoleSelected(SIDES[right].toesDigitorumBrevis)}
direction="left"
/>
)}
{hasBodyPart(SIDES[right].toesAbductorDigitiMinimi) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[right].toesAbductorDigitiMinimi]?.label}
td={trackerPartGrouped[SIDES[right].toesAbductorDigitiMinimi]}
role={SIDES[right].toesAbductorDigitiMinimi}
onClick={() => onRoleSelected(SIDES[right].toesAbductorDigitiMinimi)}
direction="left"
/>
)}

</div>
</div>
}
Expand Down
Loading