miijs 2.1.3 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -93,3 +93,4 @@ You can find FFLResHigh using a Wii U with an FTP program installed at `sys/titl
93
93
  # Credits
94
94
  - **[kazuki-4ys' MiiInfoEditorCTR](https://github.com/kazuki-4ys/kazuki-4ys.github.io/tree/master/web_apps/MiiInfoEditorCTR)** - I repurposed how to decrypt and reencrypt the QR codes from here, including repurposing the asmCrypto.js file in its entirety with very small modifications (it has since been stripped down to only include the functions this library uses). I believe I also modified the code for rendering the Mii using Nintendo's Mii Studio from here as well, though I do not remember for certain.
95
95
  - **[ariankordi's FFL.js](https://github.com/ariankordi/FFL.js/)** - Rendering Miis locally would not be possible without this library. Instructions for finding FFLResHigh are also learned from [ariankordi's FFL-Testing repository](https://github.com/ariankordi/FFL-Testing).
96
+ - **[Models Resource](https://models.spriters-resource.com/3ds/systembios/asset/306260/)** - For the bodies used in Mii rendering
@@ -0,0 +1,123 @@
1
+ // ------------------------------
2
+ // Helpers
3
+ // ------------------------------
4
+ const clamp = (v, min, max) => Math.min(max, Math.max(min, v));
5
+
6
+ // ------------------------------
7
+ // Height (0..127) <-> feet/inches
8
+ // Calibrated so height=64 -> 67 inches exactly.
9
+ // Range: 36" (3'0") .. 84" (7'0").
10
+ // ------------------------------
11
+ const HEIGHT_MIN_IN = 36;
12
+ const HEIGHT_MAX_IN = 84;
13
+ const HEIGHT_RANGE_IN = HEIGHT_MAX_IN - HEIGHT_MIN_IN;
14
+
15
+ // Calibration target: slider mid (64) should be 67"
16
+ const HEIGHT_MID_SLIDER = 64;
17
+ const HEIGHT_MID_IN = 67;
18
+
19
+ // Compute exponent k so that x0^k = y0 (bias curve, invertible)
20
+ const x0 = HEIGHT_MID_SLIDER / 127; // ~0.50394
21
+ const y0 = (HEIGHT_MID_IN - HEIGHT_MIN_IN) / HEIGHT_RANGE_IN; // 31/48 ≈ 0.64583
22
+ const HEIGHT_EXP = Math.log(y0) / Math.log(x0); // ≈ 0.638 (computed once)
23
+
24
+ /** 0..127 -> { feet, inches, totalInches } */
25
+ function miiHeightToFeetInches(heightValue) {
26
+ const hv = clamp(heightValue | 0, 0, 127);
27
+ const x = hv / 127;
28
+ const s = Math.pow(x, HEIGHT_EXP); // calibrated bias
29
+ const inches = HEIGHT_MIN_IN + s * HEIGHT_RANGE_IN;
30
+
31
+ const totalInches = Math.round(inches);
32
+ const feet = Math.floor(totalInches / 12);
33
+ const inchesR = totalInches % 12;
34
+
35
+ return { feet, inches: inchesR, totalInches };
36
+ }
37
+
38
+ /** inches -> 0..127 (inverse of the calibrated mapping) */
39
+ function inchesToMiiHeight(targetInches) {
40
+ const y = clamp((targetInches - HEIGHT_MIN_IN) / HEIGHT_RANGE_IN, 0, 1);
41
+ const x = Math.pow(y, 1 / HEIGHT_EXP);
42
+ return Math.round(x * 127);
43
+ }
44
+
45
+ // ------------------------------
46
+ // Weight (0..127) + height(0..127) <-> pounds
47
+ // Baseline by BMI; composition slider is nonlinear & invertible.
48
+ // Center (64) -> multiplier 1.0.
49
+ // ------------------------------
50
+ const BMI_AVG = 23.5; // gives ~150 lb at 67"
51
+ const WEIGHT_SPREAD = 0.35; // ±35% around baseline at extremes
52
+ const WEIGHT_GAMMA = 1.6; // steeper near ends, softer center
53
+
54
+ /** weight slider + height slider -> pounds */
55
+ function miiWeightToPounds(weightValue, heightValue) {
56
+ const wv = clamp(weightValue | 0, 0, 127);
57
+ const hv = clamp(heightValue | 0, 0, 127);
58
+
59
+ // Height in inches using the calibrated mapping
60
+ const { totalInches: H } = miiHeightToFeetInches(hv);
61
+
62
+ // BMI baseline
63
+ const base = (BMI_AVG * H * H) / 703;
64
+
65
+ // Nonlinear symmetric multiplier around 1.0 (64 -> 0 offset)
66
+ const d = clamp((wv - 64) / 63, -1, 1);
67
+ const multiplier = 1 + Math.sign(d) * WEIGHT_SPREAD * Math.pow(Math.abs(d), WEIGHT_GAMMA);
68
+
69
+ return Math.round(base * multiplier);
70
+ }
71
+
72
+ /** pounds + height slider -> weight slider (inverse of above) */
73
+ function poundsToMiiWeight(pounds, heightValue) {
74
+ const hv = clamp(heightValue | 0, 0, 127);
75
+ const { totalInches: H } = miiHeightToFeetInches(hv);
76
+ const base = (BMI_AVG * H * H) / 703;
77
+
78
+ // Guard against tiny numeric drift outside the spread
79
+ const mult = clamp(pounds / base, 1 - WEIGHT_SPREAD * 1.0001, 1 + WEIGHT_SPREAD * 1.0001);
80
+
81
+ let d;
82
+ if (Math.abs(mult - 1) < 1e-9) {
83
+ d = 0;
84
+ } else if (mult > 1) {
85
+ d = Math.pow((mult - 1) / WEIGHT_SPREAD, 1 / WEIGHT_GAMMA);
86
+ } else {
87
+ d = -Math.pow((1 - mult) / WEIGHT_SPREAD, 1 / WEIGHT_GAMMA);
88
+ }
89
+
90
+ const wv = Math.round(64 + 63 * clamp(d, -1, 1));
91
+ return clamp(wv, 0, 127);
92
+ }
93
+
94
+ // ------------------------------
95
+ // Quick checks (should match your expectations)
96
+ // ------------------------------
97
+ // Average points
98
+ // console.log(miiHeightToFeetInches(64), miiWeightToPounds(64, 64)); // ~5'7", ~150 lb
99
+ // Extremes
100
+ // console.log(miiHeightToFeetInches(0), miiWeightToPounds(0, 0)); // 3'0", ~28 lb
101
+ // console.log(miiHeightToFeetInches(127), miiWeightToPounds(127, 127)); // 7'0", ~318 lb
102
+ // Inverses
103
+ // const h = miiHeightToFeetInches(64);
104
+ // console.log(inchesToMiiHeight(h.totalInches)); // ~64
105
+ // const lbs = miiWeightToPounds(96, 64);
106
+ // console.log(lbs); // ~135
107
+ // console.log(poundsToMiiWeight(lbs, 64)); // ~96
108
+
109
+
110
+ // ------------------------------
111
+ // Quick sanity checks
112
+ // ------------------------------
113
+ // Average points
114
+ console.log(miiHeightToFeetInches(64), miiWeightToPounds(64, 64)); // ~5'0", ~150 lb
115
+ // // Extremes
116
+ console.log(miiHeightToFeetInches(0), miiWeightToPounds(0, 0));//3'0, 28 lb
117
+ console.log(miiHeightToFeetInches(127), miiWeightToPounds(127, 127));//7'0 318 lb
118
+ // // Inverses
119
+ const h = miiHeightToFeetInches(64);
120
+ console.log(inchesToMiiHeight(h.totalInches)); // ~64
121
+ const lbs = miiWeightToPounds(96, 64);
122
+ console.log(lbs);//168
123
+ console.log(poundsToMiiWeight(lbs, 64)); // ~96
package/index.js CHANGED
@@ -5,6 +5,7 @@ const { createCanvas, loadImage, ImageData } = nodeCanvas;
5
5
  const jsQR = require('jsqr');
6
6
  const Jimp = require('jimp');
7
7
  const THREE = require('three');
8
+ var GLTFLoader=null;
8
9
  const QRCodeStyling = require("qr-code-styling");
9
10
  const { JSDOM } = require("jsdom");
10
11
  const httpsLib = require('https');
@@ -2178,11 +2179,11 @@ function convertMii(jsonIn,typeTo){
2178
2179
  }
2179
2180
  miiTo.nose.type=convTables.nose3DSToWii[mii.nose.page][mii.nose.type];
2180
2181
  miiTo.mouth.type=convTables.mouth3DSToWii[mii.mouth.page][mii.mouth.type];
2181
- miiTo.mouth.color=mii.mouth.col>2?0:mii.mouth.col;
2182
+ miiTo.mouth.color=mii.mouth.color>2?0:mii.mouth.color;
2182
2183
  miiTo.hair.type=convTables.hair3DSToWii[mii.hair.page][mii.hair.type];
2183
2184
  miiTo.eyebrows.type=convTables.eyebrows3DSToWii[mii.eyebrows.page][mii.eyebrows.type];
2184
2185
  miiTo.eyes.type=convTables.eyes3DSToWii[mii.eyes.page][mii.eyes.type];
2185
- miiTo.glasses.col=mii.glasses.col;
2186
+ miiTo.glasses.color=mii.glasses.color;
2186
2187
  if(miiTo.beard.mustache.type===4){
2187
2188
  miiTo.beard.mustache.type=2;
2188
2189
  }
@@ -2210,7 +2211,7 @@ function convertMii(jsonIn,typeTo){
2210
2211
  }
2211
2212
  miiTo.eyes.squash=3;
2212
2213
  miiTo.eyebrows.squash=3;
2213
- miiTo.mouth.col=mouthCols3DS[mii.mouth.col];//qk
2214
+ miiTo.mouth.color=mii.mouth.color;
2214
2215
  miiTo.mouth.squash=3;
2215
2216
  miiTo.console="3ds";
2216
2217
  }
@@ -2263,7 +2264,7 @@ function convertMiiToStudio(jsonIn) {
2263
2264
  studioMii[0x23] = mii.mouth.squash;
2264
2265
  studioMii[0x27] = mii.mouth.yPosition;
2265
2266
  studioMii[0x29] = mii.beard.mustache.type;
2266
- studioMii[1] = mii.beard.beardType;
2267
+ studioMii[1] = mii.beard.type;
2267
2268
  studioMii[0] = mii.beard.color;
2268
2269
  if (!studioMii[0]) studioMii[0] = 8;
2269
2270
  studioMii[0x28] = mii.beard.mustache.size;
@@ -2569,7 +2570,7 @@ async function renderMiiWithStudio(jsonIn){
2569
2570
  var studioMii=convertMiiToStudio(jsonIn);
2570
2571
  return await downloadImage('https://studio.mii.nintendo.com/miis/image.png?data=' + studioMii + "&width=270&type=face");
2571
2572
  }
2572
- async function createFFLMiiIcon(data, width, height, fflRes) {
2573
+ async function createFFLMiiIcon(data, width, height, useBody, shirtColor, fflRes) {
2573
2574
  /**
2574
2575
  * Creates a Mii face render using FFL.js/Three.js/gl-headless.
2575
2576
  * @example
@@ -2609,11 +2610,18 @@ async function createFFLMiiIcon(data, width, height, fflRes) {
2609
2610
  setIsWebGL1State(!renderer.capabilities.isWebGL2); // Tell FFL.js we are WebGL1
2610
2611
 
2611
2612
  const scene = new THREE.Scene();
2612
- // scene.background = null; // Transparent background.
2613
- scene.background = new THREE.Color('white');
2614
- // (You DO NOT need to add any lights to the scene,
2615
- // unless you are using a Three.js built-in material.
2616
- // If you are, look at demo-basic.js "addLightsToScene".)
2613
+ scene.background = null; // Transparent background.
2614
+
2615
+ if(useBody){
2616
+ // After: const scene = new THREE.Scene(); scene.background = null;
2617
+ const ambient = new THREE.AmbientLight(0xffffff, 0.15);
2618
+ scene.add(ambient);
2619
+
2620
+ const rim = new THREE.DirectionalLight(0xffffff, 3);
2621
+ rim.position.set(0.5, -7, -1.0);
2622
+ scene.add(rim);
2623
+
2624
+ }
2617
2625
 
2618
2626
  let ffl, currentCharModel;
2619
2627
 
@@ -2629,11 +2637,61 @@ async function createFFLMiiIcon(data, width, height, fflRes) {
2629
2637
  // Convert Uint8Array to Buffer for struct-fu compatibility
2630
2638
  const studioBuffer = Buffer.from(studioRaw);
2631
2639
 
2632
- currentCharModel = createCharModel(studioBuffer, null,
2633
- FFLShaderMaterial, ffl.module);
2640
+ currentCharModel = createCharModel(studioBuffer, null, FFLShaderMaterial, ffl.module);
2634
2641
  initCharModelTextures(currentCharModel, renderer); // Initialize fully
2635
2642
  scene.add(currentCharModel.meshes); // Add to scene
2636
2643
 
2644
+ //Add body
2645
+ if (useBody) {
2646
+ if (typeof GLTFLoader === 'undefined' || !GLTFLoader) {
2647
+ const mod = await import('three/examples/jsm/loaders/GLTFLoader.js');
2648
+ GLTFLoader = mod.GLTFLoader;
2649
+ }
2650
+ //Read GLB from disk and parse (avoids URL/fetch issues)
2651
+ const absPath = path.resolve(__dirname, './mii-body.glb');
2652
+ const buf = fs.readFileSync(absPath);
2653
+ const arrayBuffer = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
2654
+ const loader = new GLTFLoader();
2655
+ const gltf = await new Promise((resolve, reject) => {
2656
+ loader.parse(
2657
+ arrayBuffer,
2658
+ path.dirname(absPath) + path.sep,
2659
+ resolve,
2660
+ reject
2661
+ );
2662
+ });
2663
+
2664
+ const body = gltf.scene;
2665
+
2666
+ body.position.y-=110;
2667
+
2668
+ //Recolor
2669
+ body.userData.isMiiBody = true;
2670
+ body.traverse(o => {
2671
+ if (o.isMesh) {
2672
+ if (!o.geometry.attributes.normal) {
2673
+ o.geometry.computeVertexNormals();
2674
+ }
2675
+ const isShirt = (o.name === 'mesh_1_');
2676
+ o.material?.dispose?.();
2677
+ o.material = new THREE.MeshLambertMaterial({
2678
+ //["Red", "Orange", "Yellow", "Lime", "Green", "Blue", "Cyan", "Pink", "Purple", "Brown", "White", "Black"]
2679
+ color: isShirt ? [0xFF2400,0xF08000,0xFFD700,0xAAFF00,0x008000,0x0000FF,0x00D7FF,0xFF69B4,0x7F00FF,0x6F4E37,0xFFFFFF,0x303030][shirtColor] : 0x808080,
2680
+ emissive: isShirt ? 0x330000 : 0x222222,
2681
+ emissiveIntensity: 0.0
2682
+ });
2683
+ o.material.side = THREE.DoubleSide;
2684
+ o.material.needsUpdate = true;
2685
+ }
2686
+ });
2687
+
2688
+
2689
+
2690
+ // (6) Add to scene
2691
+ scene.add(body);
2692
+ }
2693
+
2694
+
2637
2695
  // Use the camera for an icon pose.
2638
2696
  const camera = getCameraForViewType(ViewType.MakeIcon);
2639
2697
 
@@ -2641,11 +2699,16 @@ async function createFFLMiiIcon(data, width, height, fflRes) {
2641
2699
  camera.projectionMatrix.elements[5] *= -1; // Flip the camera Y axis.
2642
2700
  // When flipping the camera, the triangles are in the wrong direction.
2643
2701
  scene.traverse(mesh => {
2644
- if (mesh.isMesh && mesh.material.side === THREE.FrontSide)
2645
- // Fix triangle winding by changing the culling (side).
2646
- mesh.material.side = THREE.BackSide;
2702
+ if (
2703
+ mesh.isMesh &&
2704
+ mesh.material.side === THREE.FrontSide &&
2705
+ !mesh.userData.isMiiBody
2706
+ ) {
2707
+ mesh.material.side = THREE.BackSide;
2708
+ }
2647
2709
  });
2648
2710
 
2711
+
2649
2712
  // Render the scene, and read the pixels into a buffer.
2650
2713
  renderer.render(scene, camera);
2651
2714
  const pixels = new Uint8Array(width * height * 4);
@@ -2682,7 +2745,7 @@ async function renderMii(jsonIn, fflRes=getFFLRes()){
2682
2745
  const studioMii = convertMiiToStudio(jsonIn);
2683
2746
  const width = height = 600;
2684
2747
 
2685
- return createFFLMiiIcon(studioMii, width, height, fflRes);
2748
+ return createFFLMiiIcon(studioMii, width, height, true, jsonIn.general.favoriteColor, fflRes);
2686
2749
  }
2687
2750
  async function writeWiiBin(jsonIn, outPath) {
2688
2751
  if (jsonIn.console?.toLowerCase() !== "wii") {
@@ -2991,8 +3054,8 @@ async function write3DSQR(miiJson, outPath, fflRes = getFFLRes()) {
2991
3054
  main_img.blit(canvas, 212 - 100 / 2, 212 - 100 / 2);
2992
3055
  const font = await Jimp.loadFont(Jimp.FONT_SANS_16_BLACK)
2993
3056
 
2994
- main_img.print(font, 0, 55, {
2995
- text: miiJson.name,
3057
+ main_img.print(font, 0, 70, {
3058
+ text: miiJson.meta.name,
2996
3059
  alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
2997
3060
  alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
2998
3061
  }, 424, 395);
@@ -3014,61 +3077,64 @@ async function write3DSQR(miiJson, outPath, fflRes = getFFLRes()) {
3014
3077
  return imageBuffer;
3015
3078
  }
3016
3079
  function make3DSChild(dad,mom,options={}){
3017
- if(!["3ds","wii u"].includes(dad.console?.toLowerCase())){
3080
+ if(!["3ds","wii u"].includes(dad.meta.console?.toLowerCase())){
3018
3081
  dad=convertMii(dad,"wii");
3019
3082
  }
3020
- if(!["3ds","wii u"].includes(mom.console?.toLowerCase())){
3083
+ if(!["3ds","wii u"].includes(mom.meta.console?.toLowerCase())){
3021
3084
  mom=convertMii(dad,"wii");
3022
3085
  }
3023
- var g=options.gender||Math.floor(Math.random()*2)===1?"Male":"Female";
3086
+ var g=options.gender||Math.floor(Math.random()*2);
3024
3087
  var child={
3025
- "info":{
3088
+ "general":{
3026
3089
  "birthMonth":new Date().getMonth()+1,
3027
3090
  "birthday":new Date().getDay(),
3028
3091
  "height":64,
3029
3092
  "weight":64,
3030
- "creatorName":"",
3031
3093
  "gender":g,
3032
- "name":options.name||kidNames[g][Math.floor(Math.random()*kidNames[g].length)],
3033
3094
  "favColor":options.favColor||favCols[Math.floor(Math.random()*favCols.length)]
3034
3095
  },
3096
+ "meta":{
3097
+ "name":options.name||kidNames[g][Math.floor(Math.random()*kidNames[g].length)],
3098
+ "creatorName":"",
3099
+ },
3035
3100
  "perms":{
3036
3101
  "sharing":true,
3037
3102
  "copying":true
3038
3103
  },
3039
3104
  "hair":{
3040
- "style":[8,3],//Hardcoded
3041
- "col":Math.floor(Math.random()*2)===1?dad.hair.col:mom.hair.col,
3105
+ "page":8,//Hardcoded, needs to be generated
3106
+ "type":3,// ^
3107
+ "color":Math.floor(Math.random()*2)===1?dad.hair.color:mom.hair.color,
3042
3108
  "flipped":Math.floor(Math.random()*2)===0?true:false
3043
3109
  },
3044
3110
  "face":{
3045
3111
  "shape":Math.floor(Math.random()*2)===1?dad.face.shape:mom.face.shape,
3046
3112
  "feature":Math.floor(Math.random()*2)===1?dad.face.feature:mom.face.feature,
3047
- "makeup":g==="Male"?"None":Math.floor(Math.random()*2)===1?dad.face.makeup:mom.face.makeup
3113
+ "makeup":g===0?0:Math.floor(Math.random()*2)===1?dad.face.makeup:mom.face.makeup
3048
3114
  },
3049
3115
  "eyes":Math.floor(Math.random()*2)===1?dad.eyes:mom.eyes,
3050
3116
  "eyebrows":Math.floor(Math.random()*2)===1?dad.eyebrows:mom.eyebrows,
3051
3117
  "nose":Math.floor(Math.random()*2)===1?dad.nose:mom.nose,
3052
3118
  "mouth":Math.floor(Math.random()*2)===1?dad.mouth:mom.mouth,
3053
- "facialHair":g==="Female"?{
3054
- "mustacheType": 0,
3055
- "beardType": 0,
3056
- "col": "Black",
3057
- "mustacheSize": 4,
3058
- "mustacheYPos": 10
3059
- }:Math.floor(Math.random()*2)===0?dad.facialHair:mom.facialHair,
3119
+ "beard":{//Beards can never be generated for children allegedly, confirm before finishing
3120
+ "mustache":{
3121
+ "type":0,
3122
+ "mustacheSize": 4,
3123
+ "mustacheYPos": 10
3124
+ },
3125
+ "type": 0,
3126
+ "color": 0
3127
+ },
3060
3128
  "glasses":Math.floor(Math.random()*2)===1?dad.glasses:mom.glasses,
3061
- "mole":Math.floor(Math.random()*2)===1?dad.mole:mom.mole,
3062
- "creatorName":""
3129
+ "mole":Math.floor(Math.random()*2)===1?dad.mole:mom.mole
3063
3130
  };
3064
- child.eyebrows.col=child.hair.col;
3065
- var c=[skinCols.indexOf(mom.face.col),skinCols.indexOf(dad.face.col)];
3131
+ child.eyebrows.color=child.hair.color;
3132
+ var c=[mom.face.color,dad.face.color];
3066
3133
  if(c[0]>c[1]){
3067
3134
  c[1]=c[0];
3068
- c[0]=skinCols.indexOf(dad.face.col);
3135
+ c[0]=dad.face.color;
3069
3136
  }
3070
- child.face.col=skinCols[c[0]+Math.round((c[1]-c[0])/2)];
3071
- child.name=child.info.name;
3137
+ child.face.color=c[0]+Math.round((c[1]-c[0])/2);
3072
3138
  child.type="3DS";
3073
3139
  return child;
3074
3140
  }
package/mii-body.glb ADDED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miijs",
3
- "version": "2.1.3",
3
+ "version": "2.2.1",
4
4
  "description": "Work with Mii characters in every possible way needed for your project.",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/defaultMii.json DELETED
@@ -1,188 +0,0 @@
1
- {
2
- "male":{
3
- "general": {
4
- "type":3,
5
- "birthday": 17,
6
- "birthMonth": 4,
7
- "height": 0,
8
- "weight": 0,
9
- "gender": 1,
10
- "favoriteColor": 7
11
- },
12
- "meta":{
13
- "name": "",
14
- "creatorName": "",
15
- "console":"3ds",
16
- "miiId":"148",
17
- "systemId":"148"
18
- },
19
- "perms": {
20
- "sharing": false,
21
- "copying": true,
22
- "fromCheckMiiOut": false,
23
- "mingle": true
24
- },
25
- "hair": {
26
- "page":0,
27
- "type":7,
28
- "color": 7,
29
- "flipped": false
30
- },
31
- "face": {
32
- "type": 5,
33
- "color": 0,
34
- "feature": 0,
35
- "makeup": 0
36
- },
37
- "eyes": {
38
- "page":0,
39
- "type": 9,
40
- "col": 4,
41
- "size": 1,
42
- "squash": 3,
43
- "rotation": 4,
44
- "distanceApart": 3,
45
- "yPosition": 11
46
- },
47
- "eyebrows": {
48
- "page":0,
49
- "type":5,
50
- "color":7,
51
- "size": 2,
52
- "squash": 4,
53
- "rotation": 4,
54
- "distanceApart": 4,
55
- "yPosition": 6
56
- },
57
- "nose": {
58
- "page":1,
59
- "type":0,
60
- "size": 0,
61
- "yPosition": 5
62
- },
63
- "mouth": {
64
- "page":1,
65
- "type":6,
66
- "color": 0,
67
- "size": 2,
68
- "squash": 3,
69
- "yPosition": 10
70
- },
71
- "beard": {
72
- "mustache":{
73
- "type": 0,
74
- "size": 4,
75
- "yPosition": 10
76
- },
77
- "col": 0,
78
- "type": 0
79
- },
80
- "glasses": {
81
- "type": 0,
82
- "color":0,
83
- "size": 4,
84
- "yPosition": 10
85
- },
86
- "mole": {
87
- "on": false,
88
- "size": 4,
89
- "xPosition": 2,
90
- "yPosition": 20
91
- },
92
- "name": "",
93
- "creatorName": ""
94
- },
95
- "female":{
96
- "general": {
97
- "type":3,
98
- "birthday": 17,
99
- "birthMonth": 4,
100
- "height": 0,
101
- "weight": 0,
102
- "gender": 1,
103
- "favoriteColor": 7
104
- },
105
- "meta":{
106
- "name": "",
107
- "creatorName": "",
108
- "console":"3ds",
109
- "miiId":"148",
110
- "systemId":"148"
111
- },
112
- "perms": {
113
- "sharing": false,
114
- "copying": true,
115
- "fromCheckMiiOut": false,
116
- "mingle": true
117
- },
118
- "hair": {
119
- "page":0,
120
- "type":7,
121
- "color": 7,
122
- "flipped": false
123
- },
124
- "face": {
125
- "type": 5,
126
- "color": 0,
127
- "feature": 0,
128
- "makeup": 0
129
- },
130
- "eyes": {
131
- "page":0,
132
- "type": 9,
133
- "col": 4,
134
- "size": 1,
135
- "squash": 3,
136
- "rotation": 4,
137
- "distanceApart": 3,
138
- "yPosition": 11
139
- },
140
- "eyebrows": {
141
- "page":0,
142
- "type":5,
143
- "color":7,
144
- "size": 2,
145
- "squash": 4,
146
- "rotation": 4,
147
- "distanceApart": 4,
148
- "yPosition": 6
149
- },
150
- "nose": {
151
- "page":1,
152
- "type":0,
153
- "size": 0,
154
- "yPosition": 5
155
- },
156
- "mouth": {
157
- "page":1,
158
- "type":6,
159
- "color": 0,
160
- "size": 2,
161
- "squash": 3,
162
- "yPosition": 10
163
- },
164
- "beard": {
165
- "mustache":{
166
- "type": 0,
167
- "size": 4,
168
- "yPosition": 10
169
- },
170
- "col": 0,
171
- "type": 0
172
- },
173
- "glasses": {
174
- "type": 0,
175
- "color":0,
176
- "size": 4,
177
- "yPosition": 10
178
- },
179
- "mole": {
180
- "on": false,
181
- "size": 4,
182
- "xPosition": 2,
183
- "yPosition": 20
184
- },
185
- "name": "",
186
- "creatorName": ""
187
- }
188
- }