fix: bunch of fixes

This commit is contained in:
trafficlunar 2026-03-25 21:07:28 +00:00
parent 74139dd54e
commit 86c655d7d0
10 changed files with 251 additions and 225 deletions

View file

@ -100,12 +100,7 @@ export async function POST(request: NextRequest) {
for (const key in object) { for (const key in object) {
const value = object[key as keyof SwitchMiiInstructions]; const value = object[key as keyof SwitchMiiInstructions];
if (value === null || value === undefined) { if (!value || (DEFAULT_ZERO_FIELDS.has(key) && value === 0)) {
delete object[key as keyof SwitchMiiInstructions];
continue;
}
if (DEFAULT_ZERO_FIELDS.has(key) && value === 0) {
delete object[key as keyof SwitchMiiInstructions]; delete object[key as keyof SwitchMiiInstructions];
continue; continue;
} }

View file

@ -16,16 +16,15 @@ export default function DatingPreferencesViewer({ data, onChecked }: Props) {
const genderEnum = gender.toUpperCase() as MiiGender; const genderEnum = gender.toUpperCase() as MiiGender;
return ( return (
<div className="flex gap-1.5"> <div key={gender} className="flex gap-1.5">
<input <input
key={gender}
type="checkbox" type="checkbox"
id={gender} id={gender}
className="checkbox" className="checkbox"
checked={data.includes(genderEnum)} checked={data.includes(genderEnum)}
onChange={(e) => { {...(typeof window !== "undefined" && onChecked
if (onChecked) onChecked(e, genderEnum); ? { onChange: (e: ChangeEvent<HTMLInputElement>) => onChecked(e, genderEnum) }
}} : { readOnly: true })}
/> />
<label htmlFor={gender} className="text-sm select-none"> <label htmlFor={gender} className="text-sm select-none">
{gender} {gender}

View file

@ -76,7 +76,7 @@ function TableCell({ label, children }: TableCellProps) {
} }
function Section({ name, instructions, children, isSubSection }: SectionProps) { function Section({ name, instructions, children, isSubSection }: SectionProps) {
if (typeof instructions !== "object") return null; if (typeof instructions !== "object" || !instructions) return null;
const type = "type" in instructions ? instructions.type : undefined; const type = "type" in instructions ? instructions.type : undefined;
const color = "color" in instructions ? instructions.color : undefined; const color = "color" in instructions ? instructions.color : undefined;
@ -87,7 +87,7 @@ function Section({ name, instructions, children, isSubSection }: SectionProps) {
const stretch = "stretch" in instructions ? instructions.stretch : undefined; const stretch = "stretch" in instructions ? instructions.stretch : undefined;
return ( return (
<div className={`p-3 ${isSubSection ? "mt-2" : "border-l-4 border-amber-400 bg-amber-100/50 rounded-r-lg py-2.5"}`}> <div className={`p-3 ${isSubSection ? "not-first:mt-2 pt-0!" : "border-l-4 border-amber-400 bg-amber-100/50 rounded-r-lg py-2.5"}`}>
<h3 className="font-semibold text-xl text-amber-800 mb-1">{name}</h3> <h3 className="font-semibold text-xl text-amber-800 mb-1">{name}</h3>
<table className="w-full"> <table className="w-full">
@ -154,41 +154,13 @@ export default function MiiInstructions({ instructions }: Props) {
{eyebrows && <Section name="Eyebrows" instructions={eyebrows}></Section>} {eyebrows && <Section name="Eyebrows" instructions={eyebrows}></Section>}
{eyes && ( {eyes && (
<Section name="Eyes" instructions={eyes}> <Section name="Eyes" instructions={eyes}>
{eyes.eyesType && ( <Section isSubSection name="Main" instructions={eyes.main} />
<TableCell label="Eyes Type"> <Section isSubSection name="Eyelashes Top" instructions={eyes.eyelashesTop} />
<GridPosition index={eyes.eyesType} /> <Section isSubSection name="Eyelashes Bottom" instructions={eyes.eyelashesBottom} />
</TableCell> <Section isSubSection name="Eyelid Top" instructions={eyes.eyelidTop} />
)} <Section isSubSection name="Eyelid Bottom" instructions={eyes.eyelidBottom} />
{eyes.eyelashesTop && ( <Section isSubSection name="Eyeliner" instructions={eyes.eyeliner} />
<TableCell label="Eyelashes Top Type"> <Section isSubSection name="Pupil" instructions={eyes.pupil} />
<GridPosition index={eyes.eyelashesTop} />
</TableCell>
)}
{eyes.eyelashesBottom && (
<TableCell label="Eyelashes Bottom Type">
<GridPosition index={eyes.eyelashesBottom} />
</TableCell>
)}
{eyes.eyelidTop && (
<TableCell label="Eyelid Top Type">
<GridPosition index={eyes.eyelidTop} />
</TableCell>
)}
{eyes.eyelidBottom && (
<TableCell label="Eyelid Bottom Type">
<GridPosition index={eyes.eyelidBottom} />
</TableCell>
)}
{eyes.eyeliner && (
<TableCell label="Eyeliner Type">
<GridPosition index={eyes.eyeliner} />
</TableCell>
)}
{eyes.pupil && (
<TableCell label="Pupil Type">
<GridPosition index={eyes.pupil} />
</TableCell>
)}
</Section> </Section>
)} )}
{nose && <Section name="Nose" instructions={nose}></Section>} {nose && <Section name="Nose" instructions={nose}></Section>}

View file

@ -192,7 +192,7 @@ export default async function MiiList({ searchParams, userId, inLikesPage }: Pro
{miis.map((mii) => ( {miis.map((mii) => (
<div <div
key={mii.id} key={mii.id}
className={`flex flex-col bg-zinc-50 rounded-3xl border-2 border-zinc-300 shadow-lg p-[0.8rem] transition hover:scale-105 hover:bg-cyan-100 hover:border-cyan-600 ${mii.platform === "SWITCH" ? "border-red-300" : "border-blue-200"}`} className="flex flex-col relative bg-zinc-50 rounded-3xl border-2 border-zinc-300 shadow-lg p-[0.8rem] transition hover:scale-105 hover:bg-cyan-100 hover:border-cyan-600"
> >
<Carousel <Carousel
images={[ images={[
@ -203,8 +203,15 @@ export default async function MiiList({ searchParams, userId, inLikesPage }: Pro
/> />
<div className="p-4 flex flex-col gap-1 h-full"> <div className="p-4 flex flex-col gap-1 h-full">
<Link href={`/mii/${mii.id}`} className="font-bold text-2xl line-clamp-1" title={mii.name}> <Link href={`/mii/${mii.id}`} className="relative font-bold text-2xl line-clamp-1" title={mii.name}>
{mii.name} {mii.name}
<div className="absolute right-0 top-1/2 -translate-y-1/2 text-[1.25rem] opacity-25">
{mii.platform === "SWITCH" ? (
<Icon icon="cib:nintendo-switch" className="text-red-400" />
) : (
<Icon icon="cib:nintendo-3ds" className="text-sky-400" />
)}
</div>
</Link> </Link>
<div id="tags" className="flex flex-wrap gap-1"> <div id="tags" className="flex flex-wrap gap-1">
{mii.tags.map((tag) => ( {mii.tags.map((tag) => (

View file

@ -50,47 +50,47 @@ export default function SubmitForm() {
const [platform, setPlatform] = useState<MiiPlatform>("SWITCH"); const [platform, setPlatform] = useState<MiiPlatform>("SWITCH");
const [gender, setGender] = useState<MiiGender>("MALE"); const [gender, setGender] = useState<MiiGender>("MALE");
const instructions = useRef<Partial<SwitchMiiInstructions>>({ const instructions = useRef<SwitchMiiInstructions>({
head: { type: 1, skinColor: 1 }, head: { type: null, skinColor: null },
hair: { hair: {
setType: 43, setType: null,
bangsType: null, bangsType: null,
backType: null, backType: null,
color: 0, color: null,
subColor: null, subColor: null,
subColor2: null, subColor2: null,
style: 1, style: null,
isFlipped: false, isFlipped: false,
}, },
eyebrows: { type: 28, color: 0, height: 0, distance: 0, rotation: 0, size: 0, stretch: 0 }, eyebrows: { type: null, color: null, height: null, distance: null, rotation: null, size: null, stretch: null },
eyes: { eyes: {
main: { type: 6, color: 0, height: 0, distance: 0, rotation: 0, size: 0, stretch: 0 }, main: { type: null, color: null, height: null, distance: null, rotation: null, size: null, stretch: null },
eyelashesTop: { type: 1, height: 0, distance: 0, rotation: 0, size: 0, stretch: 0 }, eyelashesTop: { type: null, height: null, distance: null, rotation: null, size: null, stretch: null },
eyelashesBottom: { type: 1, height: 0, distance: 0, rotation: 0, size: 0, stretch: 0 }, eyelashesBottom: { type: null, height: null, distance: null, rotation: null, size: null, stretch: null },
eyelidTop: { type: 1, height: 0, distance: 0, rotation: 0, size: 0, stretch: 0 }, eyelidTop: { type: null, height: null, distance: null, rotation: null, size: null, stretch: null },
eyelidBottom: { type: 1, height: 0, distance: 0, rotation: 0, size: 0, stretch: 0 }, eyelidBottom: { type: null, height: null, distance: null, rotation: null, size: null, stretch: null },
eyeliner: { type: 1, color: 0 }, eyeliner: { type: null, color: null },
pupil: { type: 1, height: 0, distance: 0, rotation: 0, size: 0, stretch: 0 }, pupil: { type: null, height: null, distance: null, rotation: null, size: null, stretch: null },
}, },
nose: { type: 6, height: 0, size: 0 }, nose: { type: null, height: null, size: null },
lips: { type: 2, color: 0, height: 0, rotation: 0, size: 0, stretch: 0, hasLipstick: false }, lips: { type: null, color: null, height: null, rotation: null, size: null, stretch: null, hasLipstick: false },
ears: { type: 1, height: 0, size: 0 }, ears: { type: null, height: null, size: null },
glasses: { type: 1, ringColor: 0, shadesColor: 0, height: 0, size: 0, stretch: 0 }, glasses: { type: null, ringColor: null, shadesColor: null, height: null, size: null, stretch: null },
other: { other: {
wrinkles1: { type: 1, height: 0, distance: 0, size: 0, stretch: 0 }, wrinkles1: { type: null, height: null, distance: null, size: null, stretch: null },
wrinkles2: { type: 1, height: 0, distance: 0, size: 0, stretch: 0 }, wrinkles2: { type: null, height: null, distance: null, size: null, stretch: null },
beard: { type: 1, color: 0 }, beard: { type: null, color: null },
moustache: { type: 1, color: 0, height: 0, isFlipped: false, size: 0, stretch: 0 }, moustache: { type: null, color: null, height: null, isFlipped: false, size: null, stretch: null },
goatee: { type: 1, color: 0 }, goatee: { type: null, color: null },
mole: { type: 1, color: 0, height: 0, distance: 0, size: 0 }, mole: { type: null, color: null, height: null, distance: null, size: null },
eyeShadow: { type: 1, color: 0, height: 0, distance: 0, size: 0, stretch: 0 }, eyeShadow: { type: null, color: null, height: null, distance: null, size: null, stretch: null },
blush: { type: 1, color: 0, height: 0, distance: 0, size: 0, stretch: 0 }, blush: { type: null, color: null, height: null, distance: null, size: null, stretch: null },
}, },
height: 0, height: null,
weight: 0, weight: null,
datingPreferences: [], datingPreferences: [],
voice: { speed: 0, pitch: 0, depth: 0, delivery: 0, tone: 0 }, voice: { speed: null, pitch: null, depth: null, delivery: null, tone: null },
personality: { movement: 0, speech: 0, energy: 0, thinking: 0, overall: 0 }, personality: { movement: null, speech: null, energy: null, thinking: null, overall: null },
}); });
const [error, setError] = useState<string | undefined>(undefined); const [error, setError] = useState<string | undefined>(undefined);

View file

@ -1,5 +1,6 @@
import { SwitchMiiInstructions } from "@/types"; import { SwitchMiiInstructions } from "@/types";
import React, { useState } from "react"; import React, { useState } from "react";
import { Icon } from "@iconify/react";
import HeadTab from "./tabs/head"; import HeadTab from "./tabs/head";
import HairTab from "./tabs/hair"; import HairTab from "./tabs/hair";
@ -11,10 +12,9 @@ import EarsTab from "./tabs/ears";
import GlassesTab from "./tabs/glasses"; import GlassesTab from "./tabs/glasses";
import OtherTab from "./tabs/other"; import OtherTab from "./tabs/other";
import MiscTab from "./tabs/misc"; import MiscTab from "./tabs/misc";
import { Icon } from "@iconify/react";
interface Props { interface Props {
instructions: React.RefObject<Partial<SwitchMiiInstructions>>; instructions: React.RefObject<SwitchMiiInstructions>;
} }
type Tab = "head" | "hair" | "eyebrows" | "eyes" | "nose" | "lips" | "ears" | "glasses" | "other" | "misc"; type Tab = "head" | "hair" | "eyebrows" | "eyes" | "nose" | "lips" | "ears" | "glasses" | "other" | "misc";
@ -48,8 +48,6 @@ export const TAB_COMPONENTS: Record<Tab, React.ComponentType<any>> = {
export default function MiiEditor({ instructions }: Props) { export default function MiiEditor({ instructions }: Props) {
const [tab, setTab] = useState<Tab>("head"); const [tab, setTab] = useState<Tab>("head");
const ActiveTab = TAB_COMPONENTS[tab];
return ( return (
<> <>
<div className="w-full aspect-video flex bg-orange-100 border-2 border-orange-200 rounded-xl overflow-hidden"> <div className="w-full aspect-video flex bg-orange-100 border-2 border-orange-200 rounded-xl overflow-hidden">

View file

@ -15,7 +15,7 @@ export default function NumberInputs({ target }: Props) {
return ( return (
<div className="grid grid-rows-5 min-h-0"> <div className="grid grid-rows-5 min-h-0">
{target.height != undefined && ( {target.height !== undefined && (
<div className="w-full"> <div className="w-full">
<label htmlFor="height" className="text-xs"> <label htmlFor="height" className="text-xs">
Height Height
@ -36,7 +36,7 @@ export default function NumberInputs({ target }: Props) {
</div> </div>
)} )}
{target.distance != undefined && ( {target.distance !== undefined && (
<div className="w-full"> <div className="w-full">
<label htmlFor="distance" className="text-xs"> <label htmlFor="distance" className="text-xs">
Distance Distance
@ -57,7 +57,7 @@ export default function NumberInputs({ target }: Props) {
</div> </div>
)} )}
{target.rotation != undefined && ( {target.rotation !== undefined && (
<div className="w-full"> <div className="w-full">
<label htmlFor="rotation" className="text-xs"> <label htmlFor="rotation" className="text-xs">
Rotation Rotation
@ -78,7 +78,7 @@ export default function NumberInputs({ target }: Props) {
</div> </div>
)} )}
{target.size != undefined && ( {target.size !== undefined && (
<div className="w-full"> <div className="w-full">
<label htmlFor="size" className="text-xs"> <label htmlFor="size" className="text-xs">
Size Size
@ -99,7 +99,7 @@ export default function NumberInputs({ target }: Props) {
</div> </div>
)} )}
{target.stretch != undefined && ( {target.stretch !== undefined && (
<div className="w-full"> <div className="w-full">
<label htmlFor="stretch" className="text-xs"> <label htmlFor="stretch" className="text-xs">
Stretch Stretch

View file

@ -93,10 +93,11 @@ export default function HeadTab({ instructions }: Props) {
<DatingPreferencesViewer <DatingPreferencesViewer
data={datingPreferences} data={datingPreferences}
onChecked={(e, gender) => { onChecked={(e, gender) => {
setDatingPreferences((prev) => setDatingPreferences((prev) => {
e.target.checked ? (prev.includes(gender) ? prev : [...prev, gender]) : prev.filter((p) => p !== gender), const updated = e.target.checked ? (prev.includes(gender) ? prev : [...prev, gender]) : prev.filter((p) => p !== gender);
); instructions.current.datingPreferences = updated;
instructions.current.datingPreferences = datingPreferences; return updated;
});
}} }}
/> />
</div> </div>

View file

@ -113,13 +113,9 @@ export const switchMiiInstructionsSchema = z
.optional(), .optional(),
eyes: z eyes: z
.object({ .object({
eyesType: z.number().int().min(0).max(120).optional(), main: z
eyelashesTop: z.number().int().min(0).max(5).optional(), .object({
eyelashesBottom: z.number().int().min(0).max(1).optional(), type: z.number().int().min(0).max(120).optional(),
eyelidTop: z.number().int().min(0).max(2).optional(),
eyelidBottom: z.number().int().min(0).max(2).optional(),
eyeliner: z.number().int().min(0).max(1).optional(),
pupil: z.number().int().min(0).max(9).optional(),
color: colorSchema, color: colorSchema,
height: geometrySchema, height: geometrySchema,
distance: geometrySchema, distance: geometrySchema,
@ -128,6 +124,64 @@ export const switchMiiInstructionsSchema = z
stretch: geometrySchema, stretch: geometrySchema,
}) })
.optional(), .optional(),
eyelashesTop: z
.object({
type: z.number().int().min(0).max(5).optional(),
height: geometrySchema,
distance: geometrySchema,
rotation: geometrySchema,
size: geometrySchema,
stretch: geometrySchema,
})
.optional(),
eyelashesBottom: z
.object({
type: z.number().int().min(0).max(1).optional(),
height: geometrySchema,
distance: geometrySchema,
rotation: geometrySchema,
size: geometrySchema,
stretch: geometrySchema,
})
.optional(),
eyelidTop: z
.object({
type: z.number().int().min(0).max(2).optional(),
height: geometrySchema,
distance: geometrySchema,
rotation: geometrySchema,
size: geometrySchema,
stretch: geometrySchema,
})
.optional(),
eyelidBottom: z
.object({
type: z.number().int().min(0).max(2).optional(),
height: geometrySchema,
distance: geometrySchema,
rotation: geometrySchema,
size: geometrySchema,
stretch: geometrySchema,
})
.optional(),
eyeliner: z
.object({
type: z.number().int().min(0).max(1).optional(),
color: colorSchema,
})
.optional(),
pupil: z
.object({
type: z.number().int().min(0).max(9).optional(),
height: geometrySchema,
distance: geometrySchema,
rotation: geometrySchema,
size: geometrySchema,
stretch: geometrySchema,
})
.optional(),
})
.optional(),
nose: z nose: z
.object({ .object({
type: z.number().int().min(0).max(31).optional(), type: z.number().int().min(0).max(31).optional(),
@ -261,11 +315,11 @@ export const switchMiiInstructionsSchema = z
.optional(), .optional(),
personality: z personality: z
.object({ .object({
movement: z.number().int().min(1).max(8).optional(), movement: z.number().int().min(0).max(5).optional(),
speech: z.number().int().min(1).max(8).optional(), speech: z.number().int().min(0).max(5).optional(),
energy: z.number().int().min(1).max(8).optional(), energy: z.number().int().min(0).max(5).optional(),
thinking: z.number().int().min(1).max(8).optional(), thinking: z.number().int().min(0).max(5).optional(),
overall: z.number().int().min(1).max(8).optional(), overall: z.number().int().min(0).max(5).optional(),
}) })
.optional(), .optional(),
}) })

230
src/types.d.ts vendored
View file

@ -4,182 +4,182 @@ import { DefaultSession } from "next-auth";
// Some types have different options disabled, we're ignoring them for now // Some types have different options disabled, we're ignoring them for now
interface SwitchMiiInstructions { interface SwitchMiiInstructions {
head: { head: {
type: number; // 16 types, default is 2 type: number | null; // 16 types, default is 2
skinColor: number; // Additional 14 are not in color menu, default is 2 skinColor: number | null; // Additional 14 are not in color menu, default is 2
}; };
hair: { hair: {
setType: number | null; // 245 types, default is 43 setType: number | null; // 245 types, default is 43
bangsType: number | null; // 83 types, default is none, if a set is selected, set bangs and back to none and vice-versa bangsType: number | null; // 83 types, default is none, if a set is selected, set bangs and back to none and vice-versa
backType: number | null; // 111 types, default is none, same here (set related) backType: number | null; // 111 types, default is none, same here (set related)
color: number; color: number | null;
subColor: number | null; // Default is none subColor: number | null; // Default is none
subColor2: number | null; // Only used when bangs/back is selected subColor2: number | null; // Only used when bangs/back is selected
style: number | null; // is this different for each hair? style: number | null; // is this different for each hair?
isFlipped: boolean; // Only for sets and fringe isFlipped: boolean; // Only for sets and fringe
}; };
eyebrows: { eyebrows: {
type: number; // 1 is None, 43 types, default is 28 type: number | null; // 1 is None, 43 types, default is 28
color: number; color: number | null;
height: number; height: number | null;
distance: number; distance: number | null;
rotation: number; rotation: number | null;
size: number; size: number | null;
stretch: number; stretch: number | null;
}; };
eyes: { eyes: {
main: { main: {
type: number; // 1 is None, 121 types default is 6 type: number | null; // 1 is None, 121 types default is 6
color: number; color: number | null;
height: number; height: number | null;
distance: number; distance: number | null;
rotation: number; rotation: number | null;
size: number; size: number | null;
stretch: number; stretch: number | null;
}; };
eyelashesTop: { eyelashesTop: {
type: number; // 6 types, default is 1 type: number | null; // 6 types, default is 1
height: number; height: number | null;
distance: number; distance: number | null;
rotation: number; rotation: number | null;
size: number; size: number | null;
stretch: number; stretch: number | null;
}; };
eyelashesBottom: { eyelashesBottom: {
type: number; // 2 types, default is 1 type: number | null; // 2 types, default is 1
height: number; height: number | null;
distance: number; distance: number | null;
rotation: number; rotation: number | null;
size: number; size: number | null;
stretch: number; stretch: number | null;
}; };
eyelidTop: { eyelidTop: {
type: number; // 3 types, default is 1 type: number | null; // 3 types, default is 1
height: number; height: number | null;
distance: number; distance: number | null;
rotation: number; rotation: number | null;
size: number; size: number | null;
stretch: number; stretch: number | null;
}; };
eyelidBottom: { eyelidBottom: {
type: number; // 3 types, default is 1 type: number | null; // 3 types, default is 1
height: number; height: number | null;
distance: number; distance: number | null;
rotation: number; rotation: number | null;
size: number; size: number | null;
stretch: number; stretch: number | null;
}; };
eyeliner: { eyeliner: {
type: number; // 2 types, default is 1 type: number | null; // 2 types, default is 1
color: number; color: number | null;
}; };
pupil: { pupil: {
type: number; // 10 types, default is 1 type: number | null; // 10 types, default is 1
height: number; height: number | null;
distance: number; distance: number | null;
rotation: number; rotation: number | null;
size: number; size: number | null;
stretch: number; stretch: number | null;
}; };
}; };
nose: { nose: {
type: number; // 1 is None, 32 types, default is 6 type: number | null; // 1 is None, 32 types, default is 6
height: number; height: number | null;
size: number; size: number | null;
}; };
lips: { lips: {
type: number; // 1 is None, 53 types, default is 2 type: number | null; // 1 is None, 53 types, default is 2
color: number; color: number | null;
height: number; height: number | null;
rotation: number; rotation: number | null;
size: number; size: number | null;
stretch: number; stretch: number | null;
hasLipstick: boolean; hasLipstick: boolean;
}; };
ears: { ears: {
type: number; // 5 types, default is 1 type: number | null; // 5 types, default is 1
height: number; // Does not work for default height: number | null; // Does not work for default
size: number; // Does not work for default size: number | null; // Does not work for default
}; };
glasses: { glasses: {
type: number; // NOTE: THERE IS A GAP AT 40!!! 1 is None, 58 types, default is 1 type: number | null; // NOTE: THERE IS A GAP AT 40!!! 1 is None, 58 types, default is 1
ringColor: number; ringColor: number | null;
shadesColor: number; // Only works after gap shadesColor: number | null; // Only works after gap
height: number; height: number | null;
size: number; size: number | null;
stretch: number; stretch: number | null;
}; };
other: { other: {
// names were assumed // names were assumed
wrinkles1: { wrinkles1: {
type: number; // 9 types, default is 1 type: number | null; // 9 types, default is 1
height: number; height: number | null;
distance: number; distance: number | null;
size: number; size: number | null;
stretch: number; stretch: number | null;
}; };
wrinkles2: { wrinkles2: {
type: number; // 15 types, default is 1 type: number | null; // 15 types, default is 1
height: number; height: number | null;
distance: number; distance: number | null;
size: number; size: number | null;
stretch: number; stretch: number | null;
}; };
beard: { beard: {
type: number; // 15 types, default is 1 type: number | null; // 15 types, default is 1
color: number; color: number | null;
}; };
moustache: { moustache: {
type: number; // 16 types, default is 1 type: number | null; // 16 types, default is 1
color: number; // is this same as hair? color: number | null; // is this same as hair?
height: number; height: number | null;
isFlipped: boolean; isFlipped: boolean;
size: number; size: number | null;
stretch: number; stretch: number | null;
}; };
goatee: { goatee: {
type: number; // 14 types, default is 1 type: number | null; // 14 types, default is 1
color: number; color: number | null;
}; };
mole: { mole: {
type: number; // 2 types, default is 1 type: number | null; // 2 types, default is 1
color: number; // is this same as hair? color: number | null; // is this same as hair?
height: number; height: number | null;
distance: number; distance: number | null;
size: number; size: number | null;
}; };
eyeShadow: { eyeShadow: {
type: number; // 4 types, default is 1 type: number | null; // 4 types, default is 1
color: number; color: number | null;
height: number; height: number | null;
distance: number; distance: number | null;
size: number; size: number | null;
stretch: number; stretch: number | null;
}; };
blush: { blush: {
type: number; // 8 types, default is 1 type: number | null; // 8 types, default is 1
color: number; color: number | null;
height: number; height: number | null;
distance: number; distance: number | null;
size: number; size: number | null;
stretch: number; stretch: number | null;
}; };
}; };
// makeup, use video? // makeup, use video?
height: number; height: number | null;
weight: number; weight: number | null;
datingPreferences: MiiGender[]; datingPreferences: MiiGender[];
voice: { voice: {
speed: number; speed: number | null;
pitch: number; pitch: number | null;
depth: number; depth: number | null;
delivery: number; delivery: number | null;
tone: number; // 1 to 6 tone: number | null; // 1 to 6
}; };
personality: { personality: {
movement: number; // 8 levels, slow to quick movement: number | null; // 8 levels, slow to quick
speech: number; // 8 levels, polite to honest speech: number | null; // 8 levels, polite to honest
energy: number; // 8 levels, flat to varied energy: number | null; // 8 levels, flat to varied
thinking: number; // 8 levels, serious to chill thinking: number | null; // 8 levels, serious to chill
overall: number; // 8 levels, normal to quirky overall: number | null; // 8 levels, normal to quirky
}; };
} }