reze-engine 0.66.4 → 0.67.0

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/dist/engine.js CHANGED
@@ -36,7 +36,7 @@ import { sceneTargets as sceneTargetsFor, sceneColorFormats, setMrtIds, mrtIdsEn
36
36
  import { LIGHT_GRID_BASE, LIGHT_HEADER, LIGHT_STRIDE, LIGHTS_FLOATS, MAX_LIGHTS, buildLightEmitShader, hasLightEmit, } from "./shaders/lights";
37
37
  import { buildLightGrid } from "./light-grid";
38
38
  import { groundShaderWgsl, GROUND_NOISE_BAKE_WGSL, GROUND_NOISE_SIZE } from "./shaders/passes/ground";
39
- import { outlineShaderWgsl, RZ_OUTLINE_DISSOLVE_OFFSET } from "./shaders/passes/outline";
39
+ import { outlineShaderWgsl, RZ_OUTLINE_COLOR_OFFSET, RZ_OUTLINE_DISSOLVE_OFFSET, RZ_OUTLINE_SHADOW_OFFSET, RZ_OUTLINE_TEXTURED_OFFSET, RZ_OUTLINE_WIDTH_OFFSET, } from "./shaders/passes/outline";
40
40
  import { transparentDepthPrepassWgsl } from "./shaders/passes/depth-prepass";
41
41
  import { SELECTION_MASK_SHADER_WGSL, SELECTION_EDGE_SHADER_WGSL } from "./shaders/passes/selection";
42
42
  import { GIZMO_SHADER_WGSL } from "./shaders/passes/gizmo";
@@ -101,7 +101,7 @@ const PRESET_NAME_HINTS = [
101
101
  "hair", "ahoge", "bang",
102
102
  ],
103
103
  ],
104
- ["body", ["肌", "皮肤", "skin"]],
104
+ ["body", ["肌", "皮肤", "skin", "指甲", "nail"]],
105
105
  ["metal", ["金属", "メタル", "metal", "earring", "耳环", "耳環"]],
106
106
  [
107
107
  "cloth_smooth",
@@ -146,6 +146,10 @@ const PRESET_NAME_HINTS = [
146
146
  ],
147
147
  ],
148
148
  ];
149
+ // Whole names that are body parts — skin by another name. Whole, never
150
+ // substrings: 手 alone is a hand, inside 手套 (gloves) or 手镯 (a bracelet) it is
151
+ // what the hand wears; 足 is a leg, 足袋 a sock.
152
+ const BODY_PART_NAMES = new Set(["手", "手部", "腕", "足", "脚", "腿", "爪", "hand", "hands", "arm", "arms", "leg", "legs", "body"]);
149
153
  // Resolve a material name to a style category (override map first, then name hints), or
150
154
  // null if nothing matches — a null-resolving material stays ungrouped (neutral default).
151
155
  function resolvePreset(materialName, map) {
@@ -156,6 +160,8 @@ function resolvePreset(materialName, map) {
156
160
  }
157
161
  }
158
162
  const lower = materialName.toLowerCase();
163
+ if (BODY_PART_NAMES.has(lower.replace(/[\s_.\-0-9]+$/, "")))
164
+ return "body";
159
165
  for (const [preset, hints] of PRESET_NAME_HINTS) {
160
166
  for (const hint of hints) {
161
167
  if (lower.includes(hint))
@@ -245,6 +251,7 @@ export const DEFAULT_DEPTH_OF_FIELD_OPTIONS = {
245
251
  export const DEFAULT_VIEW_TRANSFORM = {
246
252
  exposure: 0,
247
253
  gamma: 1.0,
254
+ contrast: 1.4,
248
255
  transform: "soft",
249
256
  };
250
257
  const NEUTRAL_GRADE_CHANNEL = 0.5;
@@ -1071,7 +1078,7 @@ export class Engine {
1071
1078
  // 15 × vec4f — see the viewU comment in composite.ts. The last one is the
1072
1079
  // camera's world position, which is what lets a foreground effect turn the
1073
1080
  // depth it is handed into a PLACE (bgWorldPos) rather than a distance.
1074
- this.compositeUniformData = new Float32Array(60);
1081
+ this.compositeUniformData = new Float32Array(64);
1075
1082
  /** Composite background (display-space sRGB 0–1) — null = transparent canvas. */
1076
1083
  this.backgroundColor = null;
1077
1084
  // 360 backdrop (equirectangular skybox, sampled by view ray in composite).
@@ -1337,6 +1344,25 @@ export class Engine {
1337
1344
  // cloth. The full MMD-faithful machinery (interleaved per-material hulls,
1338
1345
  // texture-alpha-modulated rims) stays in place behind setOutlineEnabled(true).
1339
1346
  this.outlineEnabled = false;
1347
+ /**
1348
+ * Every outline's width, as a multiple of what each PMX material asked for
1349
+ * (its edgeSize): 1 is the author's own, 0 draws none. A multiplier rather
1350
+ * than a width because a model's lines are not one width — the hair's rim
1351
+ * and a sleeve's crease differ on purpose, and scaling keeps that.
1352
+ *
1353
+ * A write, not a re-record: one float in each hull's uniform, so a slider
1354
+ * can drive it. Hulls built later take the current value at creation.
1355
+ */
1356
+ this.outlineWidth = 1;
1357
+ /**
1358
+ * One colour for every outline, in place of each PMX material's edge colour;
1359
+ * null hands each material its own back. Written as the edge colour is —
1360
+ * the values a PMX would carry — so a picked black is MMD's black. The
1361
+ * material's edge ALPHA is kept: only the hue is the scene's.
1362
+ *
1363
+ * A write, like setOutlineWidth: hulls built later take it at creation.
1364
+ */
1365
+ this.outlineColor = [0, 0, 0, 0];
1340
1366
  /** Distinct uncaptured validation messages → how many times each arrived. */
1341
1367
  this.gpuErrors = new Map();
1342
1368
  /** When set, render resolution is pinned to this size instead of tracking the
@@ -1353,6 +1379,25 @@ export class Engine {
1353
1379
  /** A pose pushed in from outside — see setCameraPose. Reapplied every frame,
1354
1380
  * so it outranks the orbit AND a loaded track for as long as it is set. */
1355
1381
  this.cameraPoseOverride = null;
1382
+ /**
1383
+ * The host's adjustment to a camera track, added to every pose it samples.
1384
+ *
1385
+ * A downloaded camera motion is framed for whoever it was made with: a
1386
+ * shorter model wants it lower, a wider stage wants it further back. This
1387
+ * moves the shot without touching its ANGLE — the motion's rotation and roll
1388
+ * are its choreography, and they stay the track's.
1389
+ *
1390
+ * - `target`: world units, added to the look-at point, so the whole shot
1391
+ * slides with the angle unchanged.
1392
+ * - `distance`: positive pulls the eye further back along its own line of
1393
+ * sight. VMD distances are signed (negative is behind the target, the usual
1394
+ * case), so "further" means away from zero on whichever side it is.
1395
+ * - `fov`: radians, added to the track's lens, never below a sliver.
1396
+ *
1397
+ * Only a loaded track reads it: the orbit has its own sliders, and a pose
1398
+ * forced through setCameraPose is a statement of where the camera IS.
1399
+ */
1400
+ this.cameraTrackOffset = { target: new Vec3(0, 0, 0), distance: 0, fov: 0 };
1356
1401
  /**
1357
1402
  * The per-frame bind groups, the camera's and the mirror's.
1358
1403
  *
@@ -1727,6 +1772,7 @@ export class Engine {
1727
1772
  return {
1728
1773
  exposure: partial?.exposure ?? d.exposure,
1729
1774
  gamma: partial?.gamma ?? d.gamma,
1775
+ contrast: partial?.contrast ?? d.contrast,
1730
1776
  transform: partial?.transform ?? d.transform,
1731
1777
  };
1732
1778
  }
@@ -1743,7 +1789,7 @@ export class Engine {
1743
1789
  }
1744
1790
  getViewTransformOptions() {
1745
1791
  const v = this.viewTransform;
1746
- return { exposure: v.exposure, gamma: v.gamma, transform: v.transform };
1792
+ return { exposure: v.exposure, gamma: v.gamma, contrast: v.contrast, transform: v.transform };
1747
1793
  }
1748
1794
  /**
1749
1795
  * Color-grade the tonemapped scene (ASC CDL slope/offset/power + saturation).
@@ -1853,6 +1899,8 @@ export class Engine {
1853
1899
  v.exposure = patch.exposure;
1854
1900
  if (patch.gamma !== undefined)
1855
1901
  v.gamma = patch.gamma;
1902
+ if (patch.contrast !== undefined)
1903
+ v.contrast = patch.contrast;
1856
1904
  if (patch.transform !== undefined)
1857
1905
  v.transform = patch.transform;
1858
1906
  if (this.device && this.compositeUniformBuffer) {
@@ -1922,6 +1970,9 @@ export class Engine {
1922
1970
  u[25] = Engine.VIEW_TRANSFORM_ID[v.transform] ?? 0;
1923
1971
  u[26] = this.canvas.width;
1924
1972
  u[27] = this.canvas.height;
1973
+ // The soft curve's power (viewU[15].x), the scene's own (SceneSetting._contrast).
1974
+ // Its own vec4: viewU[11..14] are the cast's positions whenever an effect runs.
1975
+ u[60] = v.contrast;
1925
1976
  // ── Grade (viewU[7..9]) ── The UI's three tonal COLORS map to ASC CDL here,
1926
1977
  // on the CPU, so the shader only ever sees slope/offset/power. Mid-gray is
1927
1978
  // neutral in all three; the signed distance from it is the amount.
@@ -1971,6 +2022,34 @@ export class Engine {
1971
2022
  // per-frame state, which is what makes that affordable.
1972
2023
  this.bundlesDirty = true;
1973
2024
  }
2025
+ setOutlineWidth(scale) {
2026
+ const v = Number.isFinite(scale) ? Math.max(0, scale) : 1;
2027
+ if (this.outlineWidth === v)
2028
+ return;
2029
+ this.outlineWidth = v;
2030
+ if (!this.device)
2031
+ return;
2032
+ const one = new Float32Array([v]);
2033
+ for (const inst of this.modelInstances.values()) {
2034
+ for (const buffer of inst.outlineUniformBuffers) {
2035
+ this.device.queue.writeBuffer(buffer, RZ_OUTLINE_WIDTH_OFFSET, one);
2036
+ }
2037
+ }
2038
+ }
2039
+ setOutlineColor(color) {
2040
+ const next = color ? [color.x, color.y, color.z, 1] : [0, 0, 0, 0];
2041
+ if (next.every((v, i) => v === this.outlineColor[i]))
2042
+ return;
2043
+ this.outlineColor = next;
2044
+ if (!this.device)
2045
+ return;
2046
+ const data = new Float32Array(next);
2047
+ for (const inst of this.modelInstances.values()) {
2048
+ for (const buffer of inst.outlineUniformBuffers) {
2049
+ this.device.queue.writeBuffer(buffer, RZ_OUTLINE_COLOR_OFFSET, data);
2050
+ }
2051
+ }
2052
+ }
1974
2053
  /**
1975
2054
  * Draw the id attachment instead of the scene.
1976
2055
  *
@@ -6766,6 +6845,8 @@ export class Engine {
6766
6845
  entries: [
6767
6846
  { binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: "uniform" } },
6768
6847
  { binding: 1, visibility: GPUShaderStage.FRAGMENT, sampler: { type: "filtering" } },
6848
+ // the key light, for a style graph's outline colour (see outline.ts)
6849
+ { binding: 2, visibility: GPUShaderStage.FRAGMENT, buffer: { type: "uniform" } },
6769
6850
  ],
6770
6851
  });
6771
6852
  // Outline per-instance reuses mainPerInstanceBindGroupLayout (same skinMats binding)
@@ -6774,6 +6855,7 @@ export class Engine {
6774
6855
  entries: [
6775
6856
  { binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: "uniform" } },
6776
6857
  { binding: 1, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: "float" } },
6858
+ { binding: 2, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: "float" } },
6777
6859
  ],
6778
6860
  });
6779
6861
  const outlinePipelineLayout = this.device.createPipelineLayout({
@@ -6790,6 +6872,7 @@ export class Engine {
6790
6872
  entries: [
6791
6873
  { binding: 0, resource: { buffer: this.cameraUniformBuffer } },
6792
6874
  { binding: 1, resource: this.materialSampler },
6875
+ { binding: 2, resource: { buffer: this.lightUniformBuffer } },
6793
6876
  ],
6794
6877
  });
6795
6878
  // The same group on the MIRROR camera. An outline is geometry expanded
@@ -6802,6 +6885,7 @@ export class Engine {
6802
6885
  entries: [
6803
6886
  { binding: 0, resource: { buffer: this.mirrorCameraBuffer } },
6804
6887
  { binding: 1, resource: this.materialSampler },
6888
+ { binding: 2, resource: { buffer: this.lightUniformBuffer } },
6805
6889
  ],
6806
6890
  });
6807
6891
  const outlineShaderModule = this.device.createShaderModule({
@@ -6971,13 +7055,14 @@ export class Engine {
6971
7055
  // strength belong to the combine step.
6972
7056
  this.compositeUniformBuffer = this.device.createBuffer({
6973
7057
  label: "composite view uniforms",
6974
- // 15 × vec4f: (exposure, invGamma, _, _) · (bloom tint, intensity) ·
7058
+ // 16 × vec4f: (exposure, invGamma, _, _) · (bloom tint, intensity) ·
6975
7059
  // (bg rgb, mode) · camera right/up/forward basis for the 360 skybox ray ·
6976
7060
  // (time, _, canvas width, canvas height) for user effects · three grade
6977
7061
  // vectors (CDL offset+contrast, power+saturation, slope+flag) · camera
6978
7062
  // world position, for an effect placing itself in the scene · four
6979
- // character positions, for one that wants to respond to the cast.
6980
- size: 240,
7063
+ // character positions, for one that wants to respond to the cast · the
7064
+ // soft curve's contrast. Shaders that stop at the cast declare 15.
7065
+ size: 256,
6981
7066
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
6982
7067
  });
6983
7068
  this.dofUniformBuffer = this.device.createBuffer({
@@ -8197,6 +8282,26 @@ export class Engine {
8197
8282
  if (this.cameraPoseOverride)
8198
8283
  this.camera.setVmdPose(this.cameraPoseOverride);
8199
8284
  }
8285
+ setCameraTrackOffset(offset) {
8286
+ const t = offset?.target;
8287
+ this.cameraTrackOffset = {
8288
+ target: new Vec3(t?.x ?? 0, t?.y ?? 0, t?.z ?? 0),
8289
+ distance: offset?.distance ?? 0,
8290
+ fov: offset?.fov ?? 0,
8291
+ };
8292
+ }
8293
+ /** A sampled track pose with the host's offset laid on. */
8294
+ offsetTrackPose(pose) {
8295
+ const o = this.cameraTrackOffset;
8296
+ if (o.distance === 0 && o.fov === 0 && o.target.x === 0 && o.target.y === 0 && o.target.z === 0)
8297
+ return pose;
8298
+ return {
8299
+ target: new Vec3(pose.target.x + o.target.x, pose.target.y + o.target.y, pose.target.z + o.target.z),
8300
+ rotation: pose.rotation,
8301
+ distance: pose.distance + Math.sign(pose.distance || -1) * o.distance,
8302
+ fov: Math.min(Math.PI * 0.95, Math.max(0.01, pose.fov + o.fov)),
8303
+ };
8304
+ }
8200
8305
  /** The pose currently forced from outside, or null when nothing is. */
8201
8306
  getCameraPoseOverride() {
8202
8307
  return this.cameraPoseOverride;
@@ -9143,6 +9248,12 @@ export class Engine {
9143
9248
  { binding: 12, resource: { buffer: this.probeUniformBuffer } },
9144
9249
  ],
9145
9250
  });
9251
+ // The recorded phases bind these groups by value (sceneView), so a rebuild
9252
+ // they never hear about leaves them drawing with the old one: the first
9253
+ // light cookie landed on the ground (re-bound each frame) and not on the
9254
+ // cast, and a swapped sky kept reflecting the one it replaced. Only init,
9255
+ // a world install and the first cookie get here, so re-recording is cheap.
9256
+ this.bundlesDirty = true;
9146
9257
  return true;
9147
9258
  }
9148
9259
  /**
@@ -12692,6 +12803,7 @@ export class Engine {
12692
12803
  dissolve: 1,
12693
12804
  materialUniformBuffers: [],
12694
12805
  outlineUniformBuffers: [],
12806
+ outlineByMaterial: new Map(),
12695
12807
  cullModelIndex: 0,
12696
12808
  // Seeded false: the first skin-matrix upload decides it, and until then the
12697
12809
  // sphere path is the safe answer (it never culls something it should not).
@@ -13229,8 +13341,12 @@ export class Engine {
13229
13341
  // every material — on the heaviest mesh in the scene that doubles the
13230
13342
  // geometry submitted per frame to draw cartoon outlines around
13231
13343
  // architecture, which is not the look anyone is after.
13344
+ // Every character material gets its hull: the PMX edge flag draws it as
13345
+ // MMD does, and a style group whose look carries an outline draws it on
13346
+ // any material (assignDrawCallGroups sets `drawn`).
13232
13347
  let outline;
13233
- if (!inst.isStage && (mat.edgeFlag & 0x10) !== 0 && mat.edgeSize > 0) {
13348
+ const pmxEdge = (mat.edgeFlag & 0x10) !== 0 && mat.edgeSize > 0;
13349
+ if (!inst.isStage) {
13234
13350
  const materialUniformData = new Float32Array([
13235
13351
  mat.edgeColor[0],
13236
13352
  mat.edgeColor[1],
@@ -13243,21 +13359,31 @@ export class Engine {
13243
13359
  // block's layout would be 32 bytes of padding per outlined material
13244
13360
  // to carry one float. See RZ_OUTLINE_DISSOLVE_OFFSET.
13245
13361
  1,
13362
+ // The scene's width multiplier, at RZ_OUTLINE_WIDTH_OFFSET.
13363
+ this.outlineWidth,
13364
+ // A style graph's outline, at RZ_OUTLINE_TEXTURED_OFFSET: none yet.
13365
+ 0,
13366
+ // The scene's colour override, at RZ_OUTLINE_COLOR_OFFSET.
13367
+ this.outlineColor[0],
13368
+ this.outlineColor[1],
13369
+ this.outlineColor[2],
13370
+ this.outlineColor[3],
13371
+ // The graph outline's shadow colour, at RZ_OUTLINE_SHADOW_OFFSET.
13372
+ 0,
13373
+ 0,
13246
13374
  0,
13247
13375
  0,
13248
13376
  ]);
13249
13377
  const outlineUniformBuffer = this.createUniformBuffer(`${prefix}outline: ${mat.name}`, materialUniformData);
13250
13378
  inst.gpuBuffers.push(outlineUniformBuffer);
13251
13379
  inst.outlineUniformBuffers.push(outlineUniformBuffer);
13252
- const outlineBindGroup = this.device.createBindGroup({
13253
- label: `${prefix}outline: ${mat.name}`,
13254
- layout: this.outlinePerMaterialBindGroupLayout,
13255
- entries: [
13256
- { binding: 0, resource: { buffer: outlineUniformBuffer } },
13257
- { binding: 1, resource: textureView },
13258
- ],
13380
+ inst.outlineByMaterial.set(mat.name, {
13381
+ buffer: outlineUniformBuffer,
13382
+ edge: materialUniformData.slice(0, 5),
13383
+ picture: textureView,
13259
13384
  });
13260
- outline = { bindGroup: outlineBindGroup };
13385
+ const outlineBindGroup = this.outlineBindGroup(`${prefix}outline: ${mat.name}`, outlineUniformBuffer, textureView, null);
13386
+ outline = { bindGroup: outlineBindGroup, pmx: pmxEdge, drawn: pmxEdge };
13261
13387
  if (!inst.outlineVertexBuffer) {
13262
13388
  const data = inst.model.getOutlineVertices();
13263
13389
  const buf = this.device.createBuffer({
@@ -14532,7 +14658,7 @@ export class Engine {
14532
14658
  // Drive the shot from the camera VMD (synced to the animated model's clock).
14533
14659
  const pose = this.cameraAnimation.sample(this.transportTime());
14534
14660
  if (pose)
14535
- this.camera.setVmdPose(pose);
14661
+ this.camera.setVmdPose(this.offsetTrackPose(pose));
14536
14662
  }
14537
14663
  // Before the cast is written, which carries every subject's dissolve to the
14538
14664
  // effects reading it.
@@ -15480,8 +15606,46 @@ export class Engine {
15480
15606
  }
15481
15607
  // Rebind each material draw call to its (successfully-installed) group's uniform buffer,
15482
15608
  // or the zero buffer when ungrouped, then re-sort by render-class draw order.
15609
+ /** A hull's per-material group: its block, the picture, the look's tint. */
15610
+ outlineBindGroup(label, buffer, picture, tint) {
15611
+ return this.device.createBindGroup({
15612
+ label,
15613
+ layout: this.outlinePerMaterialBindGroupLayout,
15614
+ entries: [
15615
+ { binding: 0, resource: { buffer } },
15616
+ { binding: 1, resource: picture },
15617
+ { binding: 2, resource: (tint ?? this.fallbackMaterialTexture).createView() },
15618
+ ],
15619
+ });
15620
+ }
15483
15621
  assignDrawCallGroups(inst, claimed) {
15484
15622
  inst.materialToGroup.clear();
15623
+ // The hulls: a group whose look carries an outline (ShaderGraph.outline)
15624
+ // draws it in place of the PMX edge; the rest keep, or get back, their own.
15625
+ for (const [name, hull] of inst.outlineByMaterial) {
15626
+ const id = claimed.get(name);
15627
+ const install = id ? inst.styleGroups.get(id) : undefined;
15628
+ const o = install?.group.graph.outline;
15629
+ const block = o
15630
+ ? new Float32Array([o.color[0], o.color[1], o.color[2], 1, o.width])
15631
+ : hull.edge;
15632
+ this.device.queue.writeBuffer(hull.buffer, 0, block);
15633
+ this.device.queue.writeBuffer(hull.buffer, RZ_OUTLINE_TEXTURED_OFFSET, new Float32Array([o ? 1 : 0]));
15634
+ if (o)
15635
+ this.device.queue.writeBuffer(hull.buffer, RZ_OUTLINE_SHADOW_OFFSET, new Float32Array([...o.shadowColor, 1]));
15636
+ const tint = o?.tint != null ? (install?.imagesByMaterial?.[name] ?? install?.images)?.[o.tint] ?? null : null;
15637
+ for (const dc of inst.drawCalls) {
15638
+ if (dc.materialName !== name || !dc.outline)
15639
+ continue;
15640
+ dc.outline.bindGroup = this.outlineBindGroup(`outline: ${name}`, hull.buffer, hull.picture, tint);
15641
+ this.bundlesDirty = true;
15642
+ const drawn = o ? o.width > 0 : dc.outline.pmx;
15643
+ if (dc.outline.drawn !== drawn) {
15644
+ dc.outline.drawn = drawn;
15645
+ this.bundlesDirty = true;
15646
+ }
15647
+ }
15648
+ }
15485
15649
  for (const dc of inst.drawCalls) {
15486
15650
  if (!dc.baseBindGroupEntries)
15487
15651
  continue; // outlines/ground are never grouped
@@ -15932,7 +16096,7 @@ export class Engine {
15932
16096
  }
15933
16097
  pass.setBindGroup(2, draw.bindGroup);
15934
16098
  this.issueDraw(pass, draw, view.args);
15935
- if (draw.outline && this.outlineEnabled && view.outlines)
16099
+ if (draw.outline?.drawn && this.outlineEnabled && view.outlines)
15936
16100
  outlined.push(draw);
15937
16101
  }
15938
16102
  // THE HULLS AFTER THE SURFACES, as MMD draws a model's edges. A hull held
@@ -21,7 +21,7 @@ export const BODY_GRAPH = {
21
21
  { id: "lit_tint", type: "hue_sat", inputs: { hue: 0.5, saturation: 1.5, value: 1.0, fac: 1.0 } },
22
22
  { id: "toon_color", type: "mix/blend" },
23
23
  { id: "bc", type: "bright_contrast", inputs: { bright: 0.1, contrast: 0.2 } },
24
- { id: "emission3", type: "vector_math/scale", inputs: { scale: 4.0 } },
24
+ { id: "emission3", type: "vector_math/scale", inputs: { scale: 3.2 } },
25
25
  { id: "warm_add", type: "math/add", inputs: { b: 0.5 } },
26
26
  { id: "warm_clamp", type: "math/clamp01" },
27
27
  {
@@ -27,7 +27,7 @@ export const CLOTH_ROUGH_GRAPH = {
27
27
  { id: "mix_003", type: "mix/blend" },
28
28
  { id: "hue_004", type: "hue_sat", inputs: { hue: 0.5, saturation: 0.800000011920929, value: 2.0, fac: 1.0 } },
29
29
  { id: "npr_overlay", type: "mix/overlay", inputs: { fac: 1.0 } },
30
- { id: "npr_emit", type: "vector_math/scale", inputs: { scale: 18.200000762939453 } },
30
+ { id: "npr_emit", type: "vector_math/scale", inputs: { scale: 14.56 } },
31
31
  { id: "noise", type: "tex_noise", inputs: { scale: 17.7 } },
32
32
  { id: "noise_ramp", type: "ramp_linear", inputs: { pos0: 0.0, pos1: 1.0 } },
33
33
  { id: "bump", type: "bump", inputs: { strength: 1.0 } },
@@ -25,7 +25,7 @@ export const CLOTH_SMOOTH_GRAPH = {
25
25
  { id: "mix_003", type: "mix/blend" },
26
26
  { id: "hue_004", type: "hue_sat", inputs: { hue: 0.5, saturation: 0.800000011920929, value: 2.0, fac: 1.0 } },
27
27
  { id: "npr_overlay", type: "mix/overlay", inputs: { fac: 1.0 } },
28
- { id: "npr_emit", type: "vector_math/scale", inputs: { scale: 18.200000762939453 } },
28
+ { id: "npr_emit", type: "vector_math/scale", inputs: { scale: 14.56 } },
29
29
  { id: "principled_base", type: "hue_sat", inputs: { hue: 0.5, saturation: 1.0, value: 0.800000011920929, fac: 1.0 } },
30
30
  {
31
31
  id: "principled",
@@ -25,7 +25,7 @@ export const FACE_GRAPH = {
25
25
  { id: "lit_tint", type: "hue_sat", inputs: { hue: 0.46000000834465027, saturation: 1.600000023841858, value: 1.5, fac: 1.0 } },
26
26
  { id: "toon_color", type: "mix/blend" },
27
27
  { id: "bc", type: "bright_contrast", inputs: { bright: 0.1, contrast: 0.2 } },
28
- { id: "emission3", type: "vector_math/scale", inputs: { scale: 2.5 } },
28
+ { id: "emission3", type: "vector_math/scale", inputs: { scale: 2.0 } },
29
29
  // ── warm rim (toon*0.5+0.5 → cardinal ramp) ──
30
30
  { id: "warm_mul", type: "math/multiply", inputs: { b: 0.5 } },
31
31
  { id: "warm_add", type: "math/add", inputs: { b: 0.5 } },
@@ -24,7 +24,7 @@ export const METAL_GRAPH = {
24
24
  { id: "mix_004", type: "mix/blend" },
25
25
  { id: "hue_004", type: "hue_sat", inputs: { hue: 0.5, saturation: 1.0, value: 2.0, fac: 1.0 } },
26
26
  { id: "npr_overlay", type: "mix/overlay", inputs: { fac: 1.0 } },
27
- { id: "npr_emit", type: "vector_math/scale", inputs: { scale: 8.100000381469727 } },
27
+ { id: "npr_emit", type: "vector_math/scale", inputs: { scale: 6.48 } },
28
28
  { id: "voro_cross", type: "vect_cross", inputs: { b: [0, 1, 0] } },
29
29
  { id: "voro", type: "tex_voronoi/color", inputs: { scale: 4.3 } },
30
30
  { id: "voro_ramp", type: "ramp_linear", inputs: { pos0: 0.0, pos1: 1.0 } },
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/graph/registry.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE3C,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEzD,KAAK,SAAS,GAAG;IACf,IAAI,EAAE,KAAK,CAAA;IACX,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,4FAA4F;IAC5F,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,yFAAyF;IACzF,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IAC9B,2FAA2F;IAC3F,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,CAAA;IAC/C,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvC,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC;sEACkE;IAClE,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AAYD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,GAAG,MAAM,CAoBhE;AAED,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,GAAG,OAAO,CAIpE;AAMD,wBAAgB,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAM1D;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAKpE;AA4GD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CA+yBlD,CAAA"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/graph/registry.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE3C,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEzD,KAAK,SAAS,GAAG;IACf,IAAI,EAAE,KAAK,CAAA;IACX,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,4FAA4F;IAC5F,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,yFAAyF;IACzF,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IAC9B,2FAA2F;IAC3F,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,CAAA;IAC/C,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvC,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC;sEACkE;IAClE,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AAYD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,GAAG,MAAM,CAoBhE;AAED,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,GAAG,OAAO,CAIpE;AAMD,wBAAgB,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAM1D;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAKpE;AAsLD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAozBlD,CAAA"}
@@ -101,7 +101,11 @@ const uberNode = (slot) => ({
101
101
  roughness: F(0.6),
102
102
  occlusion: F(1),
103
103
  normal: { type: "vector", contextDefault: "n" },
104
- direction: { type: "vector", requiresLink: true },
104
+ // The key light: this draw's, by default — the sun, or the light on the
105
+ // character's own layer — its way and its colour (the game's _LocalLightDir,
106
+ // _LocalLightColor). Linked, a look supplies its own (ag_key_light).
107
+ direction: { type: "vector", contextDefault: "l" },
108
+ light_color: { type: "color", contextDefault: "sun" },
105
109
  // Unity's v into the ramp: the property map's alpha, which picks a
106
110
  // surface's band (skin 0.702, hair and pale cloth 0.506).
107
111
  row: F(0.702),
@@ -115,23 +119,44 @@ const uberNode = (slot) => ({
115
119
  rim_in_light: F(1),
116
120
  emission: C([0, 0, 0]),
117
121
  reflection: F(1),
122
+ // THE STUDIO AMBIENT (_GlobalIlluminationOverride): the game blends a
123
+ // character's ambient from its own reflection cube's smallest mip — near
124
+ // neutral, 0.4–0.9 across the newer skins — over the scene's light, by the
125
+ // material's blend (bodies 0.8, hair 1, faces 0.5). It is what keeps a
126
+ // character clean on a coloured stage.
127
+ studio: C([0.6, 0.6, 0.6]),
128
+ studio_blend: F(0),
118
129
  // A face's SDF shade (ag_face_sdf); left at -1, the material reads N·L.
119
130
  shade: F(-1),
120
131
  // 1: the game's FACE_MODE — no GGX, the environment at a flat 0.0157.
121
132
  face: F(0),
133
+ // A face's SDF highlight (ag_face_spec), in place of GGX.
134
+ face_spec: F(0),
135
+ // 1: hair (_ANISOTROPIC_SPECULAR) — its ring (ag_hair_ring) in place of GGX,
136
+ // the environment at a flat 0.0157.
137
+ hair: F(0),
138
+ hair_spec: C([0, 0, 0]),
122
139
  },
123
140
  outputs: { color: "color" },
124
- emit: (a) => `ag_uber(${slot}u, ${a.base}, ${a.metallic}, ${a.roughness}, ${a.occlusion}, ${a.normal}, ${a.direction}, ${a.row}, ${a.receive_shadow}, ` +
125
- `${a.rim_mask}, ${a.rim_mid}, ${a.rim_width}, ${a.rim_tint}, ${a.rim_intensity}, ${a.rim_albedo}, ${a.rim_in_light}, ${a.emission}, ${a.reflection}, ${a.shade}, ${a.face}, input.worldPos, v)`,
141
+ emit: (a) => `ag_uber(${slot}u, ${a.base}, ${a.metallic}, ${a.roughness}, ${a.occlusion}, ${a.normal}, ${a.direction}, ${a.light_color}, ${a.row}, ${a.receive_shadow}, ` +
142
+ `${a.rim_mask}, ${a.rim_mid}, ${a.rim_width}, ${a.rim_tint}, ${a.rim_intensity}, ${a.rim_albedo}, ${a.rim_in_light}, ${a.emission}, ${a.reflection}, ${a.studio}, ${a.studio_blend}, ${a.shade}, ${a.face}, ${a.face_spec}, ${a.hair}, ${a.hair_spec}, input.worldPos, v)`,
126
143
  takesLight: true,
127
144
  });
128
145
  const UBER_NODES = Object.fromEntries([0, 1, 2, 3].map((s) => [`ag_uber/${s}`, uberNode(s)]));
129
- // The face's SDF shade, the image on the slot the type names — 104903's face
130
- // template (SDF_04_shaonv) by default in the AG pack.
146
+ // How much a colour reads as skin (ag_skin): what picks a surface's ramp row in
147
+ // a general look, where the game would read its property mask.
148
+ const AG_SKIN = {
149
+ inputs: { color: C([1, 1, 1], true) },
150
+ outputs: { value: "float" },
151
+ emit: (a) => `ag_skin(${a.color})`,
152
+ };
153
+ // The face's SDF shade, the image on the slot the type names. An empty slot
154
+ // reads white: the whole face takes one shade from where the key light stands
155
+ // to the head, the game's flat face for a model without its SDF.
131
156
  const faceSdfNode = (slot) => ({
132
157
  inputs: {
133
158
  uv: { type: "vector", contextDefault: "vec3f(input.uv, 0.0)" },
134
- direction: { type: "vector", requiresLink: true },
159
+ direction: { type: "vector", contextDefault: "l" },
135
160
  normal: { type: "vector", contextDefault: "n" },
136
161
  smoothness: F(0.1),
137
162
  invert: F(0),
@@ -140,6 +165,54 @@ const faceSdfNode = (slot) => ({
140
165
  emit: (a) => `ag_face_sdf(${slot}u, ${a.uv}.xy, ${a.direction}, ${a.normal}, ${a.smoothness}, ${a.invert})`,
141
166
  });
142
167
  const FACE_SDF_NODES = Object.fromEntries([0, 1, 2, 3].map((s) => [`ag_face_sdf/${s}`, faceSdfNode(s)]));
168
+ // The newer SDF (_SDFType 1): a painted face normal, not a threshold field.
169
+ const faceSdfNewNode = (slot) => ({
170
+ ...faceSdfNode(slot),
171
+ emit: (a) => `ag_face_sdf_new(${slot}u, ${a.uv}.xy, ${a.direction}, ${a.normal}, ${a.smoothness}, ${a.invert})`,
172
+ });
173
+ const FACE_SDF_NEW_NODES = Object.fromEntries([0, 1, 2, 3].map((s) => [`ag_face_sdf_new/${s}`, faceSdfNewNode(s)]));
174
+ // The face's highlight from the newer SDF's green and blue.
175
+ const faceSpecNode = (slot) => ({
176
+ inputs: {
177
+ uv: { type: "vector", contextDefault: "vec3f(input.uv, 0.0)" },
178
+ direction: { type: "vector", contextDefault: "l" },
179
+ normal: { type: "vector", contextDefault: "n" },
180
+ anisotropy: F(1),
181
+ shift: F(0),
182
+ },
183
+ outputs: { value: "float" },
184
+ emit: (a) => `ag_face_spec(${slot}u, ${a.uv}.xy, ${a.direction}, ${a.normal}, v, ${a.anisotropy}, ${a.shift})`,
185
+ });
186
+ // The hair's angel ring, the band on the slot's image.
187
+ const hairRingNode = (slot) => ({
188
+ inputs: {
189
+ uv: { type: "vector", contextDefault: "vec3f(input.uv, 0.0)" },
190
+ normal: { type: "vector", contextDefault: "n" },
191
+ color: C([1, 1, 1]),
192
+ anisotropy: F(1),
193
+ shift: F(0),
194
+ },
195
+ outputs: { color: "color" },
196
+ emit: (a) => `ag_hair_ring(${slot}u, ${a.uv}.xy, ${a.normal}, v, ${a.color}, ${a.anisotropy}, ${a.shift})`,
197
+ });
198
+ const HAIR_RING_NODES = Object.fromEntries([0, 1, 2, 3].map((s) => [`ag_hair_ring/${s}`, hairRingNode(s)]));
199
+ // The game's pupil (SimPipeline/Character/Eye): unlit relief, matcap and
200
+ // glints — slots: 0 depth, 1 normal, 2 matcap, 3 glint mask.
201
+ const AG_EYE = {
202
+ inputs: {
203
+ height_scale: F(0.2), min_layer: F(8), max_layer: F(32), intensity: F(0.9),
204
+ main_color: C([1, 1, 1]), matcap_color: C([1, 1, 1]), matcap_pow: F(1),
205
+ mask_scale: F(0.15), mask_soft: F(0.014),
206
+ mask2: F(0), mask2_color: C([1, 1, 1]), mask3: F(0), mask3_color: C([1, 1, 1]),
207
+ blink: F(0), blink_scale: F(10), scale_speed: F(0.1), rotate_speed: F(0.6), blink_angle: F(5),
208
+ level: F(1),
209
+ },
210
+ outputs: { color: "color" },
211
+ emit: (a) => `ag_eye(input.uv, n, v, input.worldPos, ${a.height_scale}, ${a.min_layer}, ${a.max_layer}, ${a.intensity}, ${a.main_color}, ` +
212
+ `${a.matcap_color}, ${a.matcap_pow}, ${a.mask_scale}, ${a.mask_soft}, ${a.mask2}, ${a.mask2_color}, ${a.mask3}, ${a.mask3_color}, ` +
213
+ `${a.blink}, ${a.blink_scale}, ${a.scale_speed}, ${a.rotate_speed}, ${a.blink_angle}, ${a.level})`,
214
+ };
215
+ const FACE_SPEC_NODES = Object.fromEntries([0, 1, 2, 3].map((s) => [`ag_face_spec/${s}`, faceSpecNode(s)]));
143
216
  // A packed property map on the slot the type names — the game's material
144
217
  // contract: R metal, G perceptual roughness (answered as smoothness, Unity's
145
218
  // word for 1 − r), B occlusion, A emission mask, each remapped through the
@@ -586,7 +659,12 @@ export const NODE_REGISTRY = {
586
659
  // Principled is one: the ramp image on the group slot named by the type.
587
660
  // Defaults are 104903's skin.
588
661
  ...UBER_NODES,
662
+ ag_skin: AG_SKIN,
589
663
  ...FACE_SDF_NODES,
664
+ ...FACE_SDF_NEW_NODES,
665
+ ...FACE_SPEC_NODES,
666
+ ag_eye: AG_EYE,
667
+ ...HAIR_RING_NODES,
590
668
  ...PROPERTY_MAP_NODES,
591
669
  /**
592
670
  * Lit — Unity's Lit (URP's PBR), term for term: what a stage, a prop or
@@ -89,6 +89,20 @@ export type ShaderGraph = {
89
89
  url: string;
90
90
  srgb?: boolean;
91
91
  } | null)[];
92
+ /**
93
+ * The look's outline, the anime game's in place of MMD's flat edge: the
94
+ * material's picture × colour, toward shadowColor where the key light leaves
95
+ * it, `width` world units wide (held 1.2–3 px of a 1920-wide frame) — an Aether
96
+ * Gazer _OutlineWidth w is w·1.3/1920·8 here. Unset, the PMX edge stands.
97
+ */
98
+ outline?: {
99
+ color: [number, number, number];
100
+ shadowColor: [number, number, number];
101
+ width: number;
102
+ /** One of `images` (its index) whose colour multiplies the outline at the
103
+ * mesh's uvs — the game's per-texel outline mask. */
104
+ tint?: number;
105
+ };
92
106
  };
93
107
  export type Diagnostic = {
94
108
  severity: "error" | "warning";
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/graph/schema.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAE9F,MAAM,MAAM,SAAS,GAAG;IACtB,kFAAkF;IAClF,EAAE,EAAE,MAAM,CAAA;IACV,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAA;IACZ,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACpC;mFAC+E;IAC/E,EAAE,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAA;CAC7C,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACtC,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CACrC,CAAA;AAED,0FAA0F;AAC1F,MAAM,MAAM,YAAY,GAAG;IACzB,+DAA+D;IAC/D,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACxC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;IACvB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,WAAW,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,CAAC,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,uEAAuE;IACvE,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACxC;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IAC1C,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;IACvB;;uFAEmF;IACnF,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC,EAAE,CAAA;CACpD,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAA;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAID,eAAO,MAAM,SAAS,MAAM,CAAA;AAC5B,eAAO,MAAM,UAAU,KAAK,CAAA"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/graph/schema.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAE9F,MAAM,MAAM,SAAS,GAAG;IACtB,kFAAkF;IAClF,EAAE,EAAE,MAAM,CAAA;IACV,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAA;IACZ,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACpC;mFAC+E;IAC/E,EAAE,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAA;CAC7C,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACtC,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CACrC,CAAA;AAED,0FAA0F;AAC1F,MAAM,MAAM,YAAY,GAAG;IACzB,+DAA+D;IAC/D,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACxC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;IACvB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,WAAW,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,CAAC,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,uEAAuE;IACvE,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACxC;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IAC1C,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;IACvB;;uFAEmF;IACnF,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC,EAAE,CAAA;IACnD;;;;;OAKG;IACH,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;QAC/B,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;QACrC,KAAK,EAAE,MAAM,CAAA;QACb;8DACsD;QACtD,IAAI,CAAC,EAAE,MAAM,CAAA;KACd,CAAA;CACF,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAA;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAID,eAAO,MAAM,SAAS,MAAM,CAAA;AAC5B,eAAO,MAAM,UAAU,KAAK,CAAA"}