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 +1 -0
- package/heightWeightConversion.js +123 -0
- package/index.js +107 -41
- package/mii-body.glb +0 -0
- package/package.json +1 -1
- package/defaultMii.json +0 -188
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
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
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
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,
|
|
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)
|
|
3086
|
+
var g=options.gender||Math.floor(Math.random()*2);
|
|
3024
3087
|
var child={
|
|
3025
|
-
"
|
|
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
|
-
"
|
|
3041
|
-
"
|
|
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===
|
|
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
|
-
"
|
|
3054
|
-
"
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
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.
|
|
3065
|
-
var c=[
|
|
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]=
|
|
3135
|
+
c[0]=dad.face.color;
|
|
3069
3136
|
}
|
|
3070
|
-
child.face.
|
|
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
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
|
-
}
|