{"version":3,"sources":["avatar-portrait.mjs"],"sourcesContent":["// avatar-portrait.mjs — the PURE half of Profile's \"Save a picture\" (the owner's Avatar Portraits choices, Oct 10).\n//\n// A still of the player's own suit, head and shoulders, in one of two views (Front, Isometric), saved as one square PNG.\n// Everything here is arithmetic and naming: which way the camera looks, where the bust sits in the frame, how big a\n// tile the GPU can draw, what the file is called. No three.js import and no DOM, so tests/avatar-portrait.test.mjs can\n// drive it in node against the real suit. The drawing itself (an offscreen WebGLRenderer and a 2D composite) is\n// renderSuitPortrait in app.js, which asks this module every question it has to answer.\n//\n// THE FIGURE'S OWN AXES (suit.js): it faces local +Z, +Y is up, and its own right arm is at -X. Every vector below is\n// in those local units, where the boots run down to -1.55, the helmet's crown tops out near +1.41 and the visor's\n// centre is at +0.98.\n\nexport const PORTRAIT_VIEWS = [\n  { id: 'front', label: 'Front' },\n  { id: 'iso',   label: 'Isometric' },\n];\nexport const PORTRAIT_BACKDROPS = [\n  { id: 'clear', label: 'Transparent' },\n  { id: 'dark',  label: 'Dark' },\n];\nexport const PORTRAIT_SIZES = [1024, 2048, 4096];\n// 2048 on a desk; 1024 on a phone or tablet, for the reason the world share dialog opens on 1080p there (shareTight in\n// app.js): two full-size canvases of a 4096 picture are 128 MB on top of the game, and iOS ends a tab for less.\nexport const defaultPortraitSize = (tight) => (tight ? 1024 : 2048);\n\n// TRUE ISOMETRIC, not \"a three-quarter view\": the camera looks down atan(1/sqrt 2) = 35.264 degrees and 45 degrees\n// round, so the three visible faces of every box are foreshortened equally — the same projection the game's kube\n// icons use — and orthographic, so near and far boxes are the same size.\nexport const ISO_ELEVATION = Math.atan(1 / Math.SQRT2);\nexport const ISO_AZIMUTH = Math.PI / 4;\n\nconst dot = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\nconst cross = (a, b) => [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];\nconst norm = (a) => { const l = Math.hypot(a[0], a[1], a[2]) || 1; return [a[0] / l, a[1] / l, a[2] / l]; };\n\n// Where the camera sits, as a unit vector from the figure toward it, and the picture's right and up axes, all in the\n// figure's local frame. right/up are built EXACTLY as three.js's Object3D.lookAt builds a camera's basis with up = +Y\n// (x = up × z, y = z × x, where z points back at the camera), so a point's picture position worked out here is the\n// one the renderer puts it at.\n//\n// THE ISOMETRIC FIGURE FACES THE VIEWER'S RIGHT (the owner's pick): its visor on the right-hand side of the picture.\n// The picture's right axis comes out as (dz, 0, -dx) for a camera direction d, so the visor (+Z) lands on the right\n// exactly when dx < 0 — the camera stands off the figure's own right side (-X), in front (+Z) and above. That makes the\n// direction (-1, 1, 1)/sqrt 3, the textbook isometric diagonal; the angles are spelled out to show it is that, and the\n// test checks the visor really does project right of the head.\nexport function viewBasis(view) {\n  let dir;\n  if (view === 'iso') {\n    const c = Math.cos(ISO_ELEVATION);\n    dir = [-c * Math.sin(ISO_AZIMUTH), Math.sin(ISO_ELEVATION), c * Math.cos(ISO_AZIMUTH)];\n  } else dir = [0, 0, 1];                                   // front: straight down the figure's facing axis, no tilt\n  const right = norm(cross([0, 1, 0], dir));\n  const up = cross(dir, right);\n  return { dir, right, up };\n}\n// A local point's place in the picture plane: [along the picture's right, along its up], in local units.\nexport const projectPoint = (p, basis) => [dot(p, basis.right), dot(p, basis.up)];\n\n// ---- THE BUST ---------------------------------------------------------------------------------------------------\n// HEAD AND SHOULDERS, measured off the POSED figure rather than a fixed slice of local space. A crouch drops the head\n// a third of a unit and leans it forward, and a fixed window would have cut it low in the frame; a wave raises an arm\n// past the helmet's side. So the frame hangs from the top of the head, wherever the pose put it:\n//   - its top edge is BUST_TOP_ABOVE_HEAD above the head box's centre, in the picture's own up axis, which keeps the\n//     visor (just under that centre) at the same height in the frame whatever the pose — but never less than\n//     BUST_PAD_TOP above the highest corner of the helmet, which a lean tips up at the back;\n//   - it is BUST_HALF tall either side of its centre (half the square's side, in local units), which from that top\n//     puts the cut through the torso just below the chest band and the visor's centre in the upper third (front view:\n//     the frame runs about -0.39 … 1.61 for the standing figure, the owner's \"-0.36 … 1.6 with a little margin\");\n//   - it is centred left-right on the head, slides sideways if anything in the frame — a raised arm, arms reaching\n//     forward — would come nearer the side than BUST_PAD_SIDE, and grows (down and out, never up) only if it must.\n// The same BUST_HALF in both views means the Front and the Isometric pictures of one suit are drawn at the same scale\n// (all but a crouch seen isometrically, which is drawn closer: see the boots, below).\n// In the isometric view the helmet's top face takes the top of the frame, so there the visor sits nearer the middle.\nexport const BUST_HALF = 1.0;\nexport const BUST_TOP_ABOVE_HEAD = 0.56;\nexport const BUST_PAD_TOP = 0.1;\nexport const BUST_PAD_SIDE = 0.12;\nexport const BUST_PAD_LOW = 0.06;\nexport const BUST_HALF_MIN = 0.75;\nexport function bustFrame(parts, view) {\n  const B = viewBasis(view);\n  const head = (parts.head || []).map((p) => projectPoint(p, B));\n  const body = (parts.body || []).map((p) => projectPoint(p, B));\n  if (!head.length) throw new Error('bustFrame: no head points');\n  const centre = parts.headCentre ? projectPoint(parts.headCentre, B)\n    : [head.reduce((s, q) => s + q[0], 0) / head.length, 0];\n  const top = Math.max(centre[1] + BUST_TOP_ABOVE_HEAD, Math.max(...head.map((q) => q[1])) + BUST_PAD_TOP);\n  // Left-right: centred on the head, slid sideways if something in the frame would come within BUST_PAD_SIDE of\n  // an edge (a crouch reaches its arms forward, which in the isometric view is to the right), and only WIDENED\n  // (downward and outward, the top stays put) when the content is too wide to fit even then.\n  let cu = centre[0], half = BUST_HALF;\n  for (let i = 0; i < 3; i++) {\n    const bottom = top - 2 * half;\n    let lo = cu, hi = cu;\n    for (const q of head.concat(body)) if (q[1] >= bottom && q[1] <= top) { lo = Math.min(lo, q[0]); hi = Math.max(hi, q[0]); }\n    const want = (hi - lo) / 2 + BUST_PAD_SIDE;\n    if (want > half + 1e-9) { half = want; cu = (lo + hi) / 2; continue; }\n    if (hi + BUST_PAD_SIDE > cu + half) cu = hi + BUST_PAD_SIDE - half;\n    else if (lo - BUST_PAD_SIDE < cu - half) cu = lo - BUST_PAD_SIDE + half;\n    break;\n  }\n  // NEVER DOWN TO THE BOOTS. A crouch folds the figure into less height, and the isometric camera, looking down,\n  // folds it further: there a frame of the usual size from the head reaches the boots. So if anything of the legs'\n  // lowest part (`low`: legs and boots) would show inside the frame's width above BUST_PAD_LOW from its bottom, the\n  // frame is drawn in from the bottom up (closer, never under BUST_HALF_MIN) to stop short of the boots.\n  const boots = (parts.boots || []).map((p) => projectPoint(p, B)).filter(([u]) => Math.abs(u - cu) <= half);\n  if (boots.length) {\n    const bootTop = Math.max(...boots.map((q) => q[1]));\n    if (bootTop + BUST_PAD_LOW > top - 2 * half) {\n      half = Math.max(BUST_HALF_MIN, (top - bootTop - BUST_PAD_LOW) / 2);\n      // Re-fit left-right in the smaller frame: everything if it can, and then THE HELMET whatever that costs, so\n      // when both cannot fit it is an arm's far side that the edge cuts, never the head.\n      const fit = (pts) => {\n        let lo = Infinity, hi = -Infinity;\n        for (const q of pts) if (q[1] >= top - 2 * half && q[1] <= top) { lo = Math.min(lo, q[0]); hi = Math.max(hi, q[0]); }\n        if (!(hi >= lo)) return;\n        if (hi + BUST_PAD_SIDE > cu + half) cu = hi + BUST_PAD_SIDE - half;\n        if (lo - BUST_PAD_SIDE < cu - half) cu = lo - BUST_PAD_SIDE + half;\n      };\n      fit(head.concat(body)); fit(head);\n    }\n  }\n  return { cu, cv: top - half, half, basis: B };\n}\n// Is a local point inside the frame (picture plane only; depth is the camera's business)?\nexport function inFrame(p, frame) {\n  const [u, v] = projectPoint(p, frame.basis);\n  return Math.abs(u - frame.cu) <= frame.half && Math.abs(v - frame.cv) <= frame.half;\n}\n\n// The eight corners of every box of a built suit, in the suit's parent frame, sorted by suit.js's part tags\n// (mesh.userData.part): the helmet (head, crown, visor) into `head`, torso and arms into `body`, legs and boots into\n// `low`, the boots on their own too (the frame stops short of them), and the head box's centre. Duck-typed on three.js's own objects (traverse, matrixWorld, computeBoundingBox) so this module\n// needs no three.js of its own. The suit should be the root of what is being framed, unrotated, as in the portrait.\nexport function suitBustParts(suit) {\n  if (suit.updateMatrixWorld) suit.updateMatrixWorld(true);\n  const out = { head: [], body: [], low: [], boots: [], visor: [], headCentre: null };\n  const xf = (e, x, y, z) => [e[0] * x + e[4] * y + e[8] * z + e[12], e[1] * x + e[5] * y + e[9] * z + e[13], e[2] * x + e[6] * y + e[10] * z + e[14]];\n  suit.traverse((m) => {\n    if (!m.isMesh || !m.geometry || !m.userData || !m.userData.part) return;\n    const g = m.geometry; if (!g.boundingBox) g.computeBoundingBox();\n    const { min, max } = g.boundingBox, e = m.matrixWorld.elements, part = m.userData.part;\n    const corners = [];\n    for (const x of [min.x, max.x]) for (const y of [min.y, max.y]) for (const z of [min.z, max.z]) corners.push(xf(e, x, y, z));\n    const into = part === 'head' || part === 'crown' || part === 'visor' ? out.head : part === 'torso' || part === 'arm' ? out.body : out.low;\n    into.push(...corners);\n    if (part === 'visor') out.visor.push(...corners);\n    if (part === 'boot') out.boots.push(...corners);\n    if (part === 'head') out.headCentre = xf(e, (min.x + max.x) / 2, (min.y + max.y) / 2, (min.z + max.z) / 2);\n  });\n  return out;\n}\n\n// ---- THE POSE -----------------------------------------------------------------------------------------------------\n// The pose the Profile preview has picked, held still: poseSuit run once with a long step so every blend weight has\n// settled on its target (1 - e^-50 of the way), then once more with no time at all at a fixed point of the cycle, so\n// the same suit in the same pose always makes the same picture. Wave stops with the arm at the top of its rock. Jump\n// is a one-shot in the preview, never a picked pose, so it is not here: a portrait asked for it gets Idle.\n// WALK AND SPRINT STOP PART-WAY INTO A STRIDE, not at its widest. A bust shows the stride by the arms and the lean,\n// and at full stride (phase pi/2) the isometric camera, standing above and in front, sees the trailing boot kicked up\n// behind the hips and into the bottom of the frame (measured: the sprint's boot 0.4 units inside it). A sixth of the\n// cycle for a walk and a tenth for the deeper-leaning sprint keep both boots below the cut in either view while the\n// arms still visibly swing; tests/avatar-portrait.test.mjs checks the boots for every pose and view.\nexport const PORTRAIT_POSES = {\n  idle:   { state: {} },\n  walk:   { state: { walking: true },   phase: Math.PI / 6 },\n  run:    { state: { running: true },   phase: Math.PI / 10 },\n  crouch: { state: { crouching: true } },\n  wave:   { state: { waving: true },    waveT: 0 },\n};\nexport function holdPose(suitMod, suit, pose) {\n  const P = PORTRAIT_POSES[pose] || PORTRAIT_POSES.idle;\n  const a = suitMod.makeSuitAnim();\n  suitMod.poseSuit(suit, a, 5, P.state);\n  a.phase = P.phase || 0; a.waveT = P.waveT || 0;\n  suitMod.poseSuit(suit, a, 0, P.state);\n  return a;\n}\n\n// ---- THE LOOK (\"Polished\", the owner's pick) ----------------------------------------------------------------------\n// Fixed numbers, never the world's light, so a suit saved on a dark moon looks the same as one saved in the galaxy.\n// AO: each box's vertex colours run from AO_BOTTOM at its lowest edge to AO_TOP at its highest, multiplied into the\n// material, so every face darkens toward the bottom of its box like light pooling under a ledge.\nexport const AO_TOP = 1.05, AO_BOTTOM = 0.78;\nexport const aoAt = (t) => AO_BOTTOM + (AO_TOP - AO_BOTTOM) * Math.max(0, Math.min(1, t));\n// The drop shadow, in output pixels: down a little, and in the isometric view a little left too (the light comes from\n// the figure's front-top, which in that view is the picture's upper right).\nexport function portraitShadow(view, size) {\n  return { color: 'rgba(0,0,0,0.55)', blur: Math.round(size * 0.03), dx: view === 'iso' ? -Math.round(size * 0.012) : 0, dy: Math.round(size * 0.02) };\n}\n// The visor's glow, two soft passes of the visor alone in its own colour: a wide faint one and a tight bright one.\nexport const portraitGlow = (size) => [{ blur: Math.round(size * 0.06), alpha: 0.55 }, { blur: Math.round(size * 0.022), alpha: 0.7 }];\n// The \"Dark\" backdrop: the game's deep space, a dark radial gradient warmed by the visor's colour at its centre. Stops\n// as CSS colours so the composite and a test read the same numbers.\nexport function portraitBackdrop(accent) {\n  const a = (accent >>> 0) & 0xffffff, r = (a >> 16) & 255, g = (a >> 8) & 255, b = a & 255;\n  const mix = (k, base) => [base[0] + (r - base[0]) * k, base[1] + (g - base[1]) * k, base[2] + (b - base[2]) * k].map((n) => Math.round(n));\n  const css = (c) => `rgb(${c[0]},${c[1]},${c[2]})`;\n  return { cx: 0.5, cy: 0.4, r: 0.75, stops: [[0, css(mix(0.22, [12, 15, 26]))], [0.55, css(mix(0.07, [7, 9, 16]))], [1, 'rgb(3,4,8)']] };\n}\n\n// ---- THE FILE ------------------------------------------------------------------------------------------------------\n// <in-game name>-front-2048.png / <in-game name>-iso-2048.png. The name keeps its letters in any alphabet (names.mjs\n// allows them) and loses what a filesystem would argue with, as the world share dialog's shareFileName does; spaces\n// become dashes. No name (a guest) is kubicor-suit.\nexport function portraitFileName(name, view, size) {\n  const base = String(name == null ? '' : name).replace(/[^\\p{L}\\p{M}\\p{N} _-]/gu, '').trim().replace(/\\s+/g, '-');\n  return (base || 'kubicor-suit') + '-' + (view === 'iso' ? 'iso' : 'front') + '-' + (size | 0) + '.png';\n}\n\n// ---- WHAT THIS DEVICE CAN DRAW ---------------------------------------------------------------------------------------\n// THE PICTURE IS DRAWN IN TILES, so its size is never limited by the GPU. A phone's WebGL may top out at a 4096 texture\n// and refuse a drawing buffer that size, and even where it allows one, a 4096 multisampled buffer is a few hundred\n// megabytes on top of the game. So the renderer draws squares of `tile` pixels — the largest power of two the\n// texture, renderbuffer and viewport limits all allow, capped at 2048 (1024 on a touch device) — and each is copied\n// into its place in the 2D picture. `tiles` is how many there are along a side.\nexport function portraitTilePlan(size, caps = {}, tight = false) {\n  const lim = Math.min(caps.maxTextureSize || 4096, caps.maxRenderbufferSize || 4096, caps.maxViewport || 4096, tight ? 1024 : 2048, size);\n  let tile = 64; while (tile * 2 <= lim) tile *= 2;\n  return { size, tile, tiles: Math.ceil(size / tile) };\n}\n// …WHICH LEAVES THE 2D CANVASES, which no tiling avoids: the picture has to exist whole to become a PNG. If one that\n// big cannot be had (iOS refuses past its canvas memory), the save steps down a size and says so: the sizes to try,\n// largest first, from the one asked for.\nexport const portraitSizeFallbacks = (size) => [size | 0].concat(PORTRAIT_SIZES.filter((s) => s < size).sort((a, b) => b - a));\n"],"mappings":"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","names":[],"file":"avatar-portrait.mjs"}