3d-spinner 0.9.2 → 0.9.3

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.
Files changed (97) hide show
  1. package/README.md +66 -4
  2. package/dist/animation-label.d.ts +8 -0
  3. package/dist/animation-label.js +47 -0
  4. package/dist/animation.d.ts +2 -0
  5. package/dist/animations/charged-orb.d.ts +55 -0
  6. package/dist/animations/charged-orb.js +229 -0
  7. package/dist/animations/grid-assembly.d.ts +67 -0
  8. package/dist/animations/grid-assembly.js +268 -0
  9. package/dist/animations/object-motion.d.ts +19 -7
  10. package/dist/animations/object-motion.js +38 -32
  11. package/dist/animations/particles.d.ts +110 -0
  12. package/dist/animations/particles.js +209 -0
  13. package/dist/cjs/animations/charged-orb.cjs +1334 -0
  14. package/dist/cjs/animations/grid-assembly.cjs +1498 -0
  15. package/dist/cjs/animations/object-motion.cjs +124 -43
  16. package/dist/cjs/animations/particles.cjs +1940 -0
  17. package/dist/cjs/animations/spin.cjs +4 -3
  18. package/dist/cjs/composite-animation.cjs +58 -0
  19. package/dist/cjs/engines/little-3d-engine/little-3d-engine.cjs +131 -22
  20. package/dist/cjs/engines/little-3d-engine/loaders/obj.cjs +30 -1
  21. package/dist/cjs/engines/little-3d-engine/renderers/canvas2d-textured.cjs +345 -0
  22. package/dist/cjs/engines/little-3d-engine/renderers/webgl-textured.cjs +528 -0
  23. package/dist/cjs/engines/little-3d-engine/renderers/webgpu-textured.cjs +712 -0
  24. package/dist/cjs/prefabs/prefabs.cjs +3450 -0
  25. package/dist/composite-animation.d.ts +18 -0
  26. package/dist/composite-animation.js +39 -0
  27. package/dist/engines/little-3d-engine/little-3d-engine.d.ts +17 -12
  28. package/dist/engines/little-3d-engine/little-3d-engine.js +13 -8
  29. package/dist/engines/little-3d-engine/loaders/obj.d.ts +12 -4
  30. package/dist/engines/little-3d-engine/loaders/obj.js +44 -5
  31. package/dist/engines/little-3d-engine/renderer.d.ts +7 -1
  32. package/dist/engines/little-3d-engine/renderer.js +2 -0
  33. package/dist/engines/little-3d-engine/renderers/canvas2d-textured.d.ts +20 -0
  34. package/dist/engines/little-3d-engine/renderers/canvas2d-textured.js +135 -0
  35. package/dist/engines/little-3d-engine/renderers/textured-helpers.d.ts +9 -0
  36. package/dist/engines/little-3d-engine/renderers/textured-helpers.js +35 -0
  37. package/dist/engines/little-3d-engine/renderers/webgl-textured.d.ts +43 -0
  38. package/dist/engines/little-3d-engine/renderers/webgl-textured.js +211 -0
  39. package/dist/engines/little-3d-engine/renderers/webgpu-textured.d.ts +45 -0
  40. package/dist/engines/little-3d-engine/renderers/webgpu-textured.js +300 -0
  41. package/dist/engines/little-3d-engine/renderers/webgpu.d.ts +11 -6
  42. package/dist/engines/little-3d-engine/shapes/complex/plane.d.ts +3 -0
  43. package/dist/engines/little-3d-engine/shapes/complex/plane.js +33 -0
  44. package/dist/engines/little-3d-engine/shapes/{cube.d.ts → primitives/cube.d.ts} +1 -1
  45. package/dist/engines/little-3d-engine/shapes/{octahedron.d.ts → primitives/octahedron.d.ts} +1 -1
  46. package/dist/engines/little-3d-engine/shapes/{pyramid.d.ts → primitives/pyramid.d.ts} +1 -1
  47. package/dist/engines/little-3d-engine/shapes/primitives/quad.d.ts +9 -0
  48. package/dist/engines/little-3d-engine/shapes/primitives/quad.js +18 -0
  49. package/dist/engines/little-3d-engine/shapes/{cube-sphere.d.ts → primitives/spheres/cube-sphere.d.ts} +1 -1
  50. package/dist/engines/little-3d-engine/shapes/{icosphere.d.ts → primitives/spheres/icosphere.d.ts} +1 -1
  51. package/dist/engines/little-3d-engine/shapes/{icosphere.js → primitives/spheres/icosphere.js} +1 -1
  52. package/dist/engines/little-3d-engine/shapes/{octa-sphere.d.ts → primitives/spheres/octa-sphere.d.ts} +1 -1
  53. package/dist/engines/little-3d-engine/shapes/{octa-sphere.js → primitives/spheres/octa-sphere.js} +1 -1
  54. package/dist/engines/little-3d-engine/shapes/{uv-sphere.d.ts → primitives/spheres/uv-sphere.d.ts} +1 -1
  55. package/dist/engines/little-3d-engine/shapes/{tetrahedron.d.ts → primitives/tetrahedron.d.ts} +1 -1
  56. package/dist/engines/little-3d-engine/textures/dynamic/canvas-texture.d.ts +1 -0
  57. package/dist/engines/little-3d-engine/textures/dynamic/canvas-texture.js +8 -0
  58. package/dist/engines/little-3d-engine/textures/dynamic/shine.d.ts +2 -0
  59. package/dist/engines/little-3d-engine/textures/dynamic/shine.js +14 -0
  60. package/dist/engines/little-3d-engine/textures/dynamic/star.d.ts +2 -0
  61. package/dist/engines/little-3d-engine/textures/dynamic/star.js +16 -0
  62. package/dist/engines/little-3d-engine/textures/dynamic/streak.d.ts +5 -0
  63. package/dist/engines/little-3d-engine/textures/dynamic/streak.js +20 -0
  64. package/dist/index.d.ts +2 -1
  65. package/dist/prefabs/charged-orb.d.ts +17 -0
  66. package/dist/prefabs/charged-orb.js +37 -0
  67. package/dist/prefabs/crystal-comet.d.ts +4 -0
  68. package/dist/prefabs/crystal-comet.js +41 -0
  69. package/dist/prefabs/ghost-train.d.ts +9 -0
  70. package/dist/prefabs/ghost-train.js +44 -0
  71. package/dist/prefabs/grid-assembly.d.ts +13 -0
  72. package/dist/prefabs/grid-assembly.js +15 -0
  73. package/dist/prefabs/monochrome-streak.d.ts +4 -0
  74. package/dist/prefabs/monochrome-streak.js +25 -0
  75. package/dist/prefabs/plane-star-trail.d.ts +4 -0
  76. package/dist/prefabs/plane-star-trail.js +40 -0
  77. package/dist/prefabs/prefabs.d.ts +10 -0
  78. package/dist/prefabs/prefabs.js +9 -0
  79. package/dist/prefabs/pulsing-starfield.d.ts +4 -0
  80. package/dist/prefabs/pulsing-starfield.js +27 -0
  81. package/dist/prefabs/rocket-launch.d.ts +8 -0
  82. package/dist/prefabs/rocket-launch.js +59 -0
  83. package/dist/prefabs/spinner.d.ts +7 -0
  84. package/dist/prefabs/spinner.js +17 -0
  85. package/dist/prefabs/star-swarm.d.ts +4 -0
  86. package/dist/prefabs/star-swarm.js +27 -0
  87. package/dist/prefabs/types.d.ts +46 -0
  88. package/dist/prefabs/types.js +1 -0
  89. package/dist/umd/spinner.global.js +3055 -1251
  90. package/dist/umd/spinner.global.min.js +60 -5
  91. package/package.json +42 -1
  92. /package/dist/engines/little-3d-engine/shapes/{cube.js → primitives/cube.js} +0 -0
  93. /package/dist/engines/little-3d-engine/shapes/{octahedron.js → primitives/octahedron.js} +0 -0
  94. /package/dist/engines/little-3d-engine/shapes/{pyramid.js → primitives/pyramid.js} +0 -0
  95. /package/dist/engines/little-3d-engine/shapes/{cube-sphere.js → primitives/spheres/cube-sphere.js} +0 -0
  96. /package/dist/engines/little-3d-engine/shapes/{uv-sphere.js → primitives/spheres/uv-sphere.js} +0 -0
  97. /package/dist/engines/little-3d-engine/shapes/{tetrahedron.js → primitives/tetrahedron.js} +0 -0
@@ -797,6 +797,7 @@ function orderRenderItems(items, eye) {
797
797
  return opaque.concat(transparent);
798
798
  }
799
799
  async function createRenderer(backend, options = {}) {
800
+ if (typeof backend === "function") return backend(options);
800
801
  switch (backend) {
801
802
  case "webgl":
802
803
  return new (await Promise.resolve().then(() => (init_webgl(), webgl_exports))).WebGLRenderer(options);
@@ -825,6 +826,48 @@ __export(object_motion_exports, {
825
826
  });
826
827
  module.exports = __toCommonJS(object_motion_exports);
827
828
 
829
+ // src/animation-label.ts
830
+ var LABEL_STYLE = [
831
+ "position:absolute",
832
+ "inset:0",
833
+ "display:flex",
834
+ "align-items:center",
835
+ "justify-content:center",
836
+ "pointer-events:none",
837
+ "font:700 1.6rem/1 system-ui,sans-serif",
838
+ "letter-spacing:0.02em",
839
+ "color:rgba(255,255,255,0.9)",
840
+ "text-shadow:0 1px 10px rgba(0,0,0,0.6)",
841
+ "z-index:1"
842
+ ].join(";");
843
+ function animationLabelOpacity(now, enterAt, introDurationMs, exitAt, outroDurationMs) {
844
+ if (enterAt === Infinity) return 0;
845
+ const intro = introDurationMs <= 0 ? 1 : Math.max(0, Math.min(1, (now - enterAt) / introDurationMs));
846
+ const outro = exitAt === Infinity ? 1 : outroDurationMs <= 0 ? 0 : Math.max(0, Math.min(1, 1 - (now - exitAt) / outroDurationMs));
847
+ return Math.min(intro, outro);
848
+ }
849
+ function mountAnimationLabel(target, content) {
850
+ var _a;
851
+ const container = document.createElement("div");
852
+ container.style.cssText = LABEL_STYLE;
853
+ container.setAttribute("role", "status");
854
+ if (typeof content === "string") container.textContent = content;
855
+ else if (content) {
856
+ (_a = content.style).pointerEvents || (_a.pointerEvents = "auto");
857
+ container.appendChild(content);
858
+ }
859
+ target.appendChild(container);
860
+ return {
861
+ container,
862
+ setText(value) {
863
+ if (typeof content !== "object") container.textContent = value;
864
+ },
865
+ setOpacity(value) {
866
+ container.style.opacity = String(value);
867
+ }
868
+ };
869
+ }
870
+
828
871
  // src/engines/little-3d-engine/core/camera.ts
829
872
  init_math();
830
873
  var DEFAULTS = {
@@ -875,7 +918,7 @@ function transform(init) {
875
918
  init_renderer();
876
919
  init_light();
877
920
 
878
- // src/engines/little-3d-engine/shapes/icosphere.ts
921
+ // src/engines/little-3d-engine/shapes/primitives/spheres/icosphere.ts
879
922
  init_geometry();
880
923
  var T = (1 + Math.sqrt(5)) / 2;
881
924
  var SEED_VERTICES = [
@@ -893,7 +936,7 @@ var SEED_VERTICES = [
893
936
  { x: -T, y: 0, z: 1 }
894
937
  ];
895
938
 
896
- // src/engines/little-3d-engine/shapes/octa-sphere.ts
939
+ // src/engines/little-3d-engine/shapes/primitives/spheres/octa-sphere.ts
897
940
  init_geometry();
898
941
 
899
942
  // src/engines/little-3d-engine/little-3d-engine.ts
@@ -1048,32 +1091,49 @@ var Little3dEngine = class {
1048
1091
  init_math();
1049
1092
 
1050
1093
  // src/motion/transitions.ts
1051
- function easeOutBack(delta) {
1052
- const c = 1.70158;
1053
- const u = delta - 1;
1054
- return 1 + (c + 1) * u * u * u + c * u * u;
1094
+ var DEFAULT_DISTANCE = 3.5;
1095
+ function add(a, b) {
1096
+ return { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z };
1055
1097
  }
1056
- function grow() {
1057
- return (input) => ({ size: (input.size ?? 1) * easeOutBack(input.delta) });
1098
+ function scaleVector(v, factor) {
1099
+ return { x: v.x * factor, y: v.y * factor, z: v.z * factor };
1058
1100
  }
1059
- function shrink() {
1060
- return (input) => ({ size: (input.size ?? 1) * (1 - input.delta * input.delta) });
1101
+ function vectorLength(v) {
1102
+ return Math.hypot(v.x, v.y, v.z);
1103
+ }
1104
+ function normalizeVector(v) {
1105
+ const length = vectorLength(v);
1106
+ if (length < 1e-6) return { x: 1, y: 0, z: 0 };
1107
+ return scaleVector(v, 1 / length);
1108
+ }
1109
+ function resolveDirection(input, fallback) {
1110
+ return normalizeVector(fallback ?? input.direction ?? input.velocity ?? { x: 1, y: 0, z: 0 });
1111
+ }
1112
+ function joinVelocity(input, options, durationMs) {
1113
+ const inputSpeed = input.velocity ? vectorLength(input.velocity) : 0;
1114
+ if (input.velocity && inputSpeed > 1e-6 && !options.direction) {
1115
+ return input.velocity;
1116
+ }
1117
+ const distance = options.distance ?? DEFAULT_DISTANCE;
1118
+ return scaleVector(resolveDirection(input, options.direction), distance / durationMs);
1119
+ }
1120
+ function enterFromObjectDirection(options = {}) {
1121
+ return (input) => {
1122
+ const durationMs = Math.max(1, input.durationMs);
1123
+ const velocity = joinVelocity(input, options, durationMs);
1124
+ const remaining = durationMs - input.elapsedMs;
1125
+ return { position: add(input.position, scaleVector(velocity, -remaining)) };
1126
+ };
1127
+ }
1128
+ function leaveInObjectDirection(options = {}) {
1129
+ return (input) => {
1130
+ const durationMs = Math.max(1, input.durationMs);
1131
+ const velocity = joinVelocity(input, options, durationMs);
1132
+ return { position: add(input.position, scaleVector(velocity, input.elapsedMs)) };
1133
+ };
1061
1134
  }
1062
1135
 
1063
1136
  // src/animations/object-motion.ts
1064
- var LABEL_STYLE = [
1065
- "position:absolute",
1066
- "inset:0",
1067
- "display:flex",
1068
- "align-items:center",
1069
- "justify-content:center",
1070
- "pointer-events:none",
1071
- "font:700 1.6rem/1 system-ui,sans-serif",
1072
- "letter-spacing:0.02em",
1073
- "color:rgba(255,255,255,0.9)",
1074
- "text-shadow:0 1px 10px rgba(0,0,0,0.6)",
1075
- "z-index:1"
1076
- ].join(";");
1077
1137
  var WORLD_UP = { x: 0, y: 1, z: 0 };
1078
1138
  var DEFAULT_INTRO_MS = 2100;
1079
1139
  var DEFAULT_OUTRO_MS = 2100;
@@ -1089,13 +1149,14 @@ var FACE_FORWARD = {
1089
1149
  "+y": (v) => ({ x: v.y, y: -v.x, z: v.z }),
1090
1150
  "-y": (v) => ({ x: -v.y, y: v.x, z: v.z })
1091
1151
  };
1092
- function add(a, b) {
1152
+ function add2(a, b) {
1093
1153
  return { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z };
1094
1154
  }
1095
1155
  function resolveMesh(mesh) {
1096
1156
  return typeof mesh === "function" ? mesh() : mesh;
1097
1157
  }
1098
1158
  function applyColor(mesh, color) {
1159
+ if (color === void 0) return mesh;
1099
1160
  return { vertices: mesh.vertices, faces: mesh.faces.map((face) => ({ ...face, color })) };
1100
1161
  }
1101
1162
  function faceForward(mesh, facing) {
@@ -1138,7 +1199,7 @@ function orientationFor(forward, bank) {
1138
1199
  if (Math.hypot(right.x, right.y, right.z) < 1e-4) right = { x: 0, y: 0, z: 1 };
1139
1200
  right = normalize(right);
1140
1201
  const levelUp = cross(right, fwd);
1141
- const up = add(scale(levelUp, Math.cos(bank)), scale(right, Math.sin(bank)));
1202
+ const up = add2(scale(levelUp, Math.cos(bank)), scale(right, Math.sin(bank)));
1142
1203
  const w = normalize(cross(fwd, up));
1143
1204
  return {
1144
1205
  x: Math.atan2(cross(w, fwd).z, w.z),
@@ -1175,7 +1236,7 @@ function clamp012(value) {
1175
1236
  function motionVectorAt(motion, t) {
1176
1237
  return scale(subtract(motion.positionAt(t + 1), motion.positionAt(t - 1)), 0.5);
1177
1238
  }
1178
- function resolveDirection(velocity, fallback) {
1239
+ function resolveDirection2(velocity, fallback) {
1179
1240
  return Math.hypot(velocity.x, velocity.y, velocity.z) > 1e-6 ? normalize(velocity) : fallback;
1180
1241
  }
1181
1242
  function resolveTransition(config, fallback, durationMs) {
@@ -1197,15 +1258,16 @@ var ObjectMotionAnimation = class {
1197
1258
  this.outroDirection = { x: 1, y: 0, z: 0 };
1198
1259
  const centered = centerAndScaleMesh(resolveMesh(options.mesh), options.size ?? 1);
1199
1260
  const facing = faceForward(centered, options.facing ?? "+x");
1200
- this.mesh = applyColor(facing, options.color ?? "#cbd5e1");
1261
+ this.mesh = applyColor(facing, options.color);
1201
1262
  this.motion = options.motion;
1202
1263
  this.backend = options.backend;
1203
1264
  this.transparency = options.transparency;
1204
- this.labelText = options.label;
1265
+ this.labelContent = options.label;
1266
+ this.fadeLabel = options.fadeLabel ?? true;
1205
1267
  this.tailCount = Math.max(0, Math.floor(options.tail?.count ?? 0));
1206
1268
  this.tailGap = Math.max(0, options.tail?.gapMs ?? 0);
1207
- this.intro = resolveTransition(options.intro, grow(), DEFAULT_INTRO_MS);
1208
- this.outro = resolveTransition(options.outro, shrink(), DEFAULT_OUTRO_MS);
1269
+ this.intro = resolveTransition(options.intro, enterFromObjectDirection(), DEFAULT_INTRO_MS);
1270
+ this.outro = resolveTransition(options.outro, leaveInObjectDirection(), DEFAULT_OUTRO_MS);
1209
1271
  const rotation = options.rotation;
1210
1272
  this.rotationOffset = { x: rotation?.x ?? 0, y: rotation?.y ?? 0, z: rotation?.z ?? 0 };
1211
1273
  this.rotationSpin = {
@@ -1216,7 +1278,7 @@ var ObjectMotionAnimation = class {
1216
1278
  this.hasExtraRotation = this.rotationOffset.x !== 0 || this.rotationOffset.y !== 0 || this.rotationOffset.z !== 0 || this.rotationSpin.x !== 0 || this.rotationSpin.y !== 0 || this.rotationSpin.z !== 0;
1217
1279
  }
1218
1280
  mount(target) {
1219
- target.style.position = "relative";
1281
+ if (!target.style.position) target.style.position = "relative";
1220
1282
  const engine = new Little3dEngine({
1221
1283
  backend: this.backend,
1222
1284
  camera: { position: { x: 0, y: 0, z: 3 } }
@@ -1230,11 +1292,8 @@ var ObjectMotionAnimation = class {
1230
1292
  engine.mount(target).catch((error) => {
1231
1293
  target.textContent = error instanceof Error ? error.message : String(error);
1232
1294
  });
1233
- const label = document.createElement("div");
1234
- label.style.cssText = LABEL_STYLE;
1235
- label.setAttribute("role", "status");
1236
- target.appendChild(label);
1237
- this.label = label;
1295
+ this.label = mountAnimationLabel(target, this.labelContent);
1296
+ if (this.fadeLabel) this.label.setOpacity(0);
1238
1297
  }
1239
1298
  enter(now) {
1240
1299
  if (this.started) return;
@@ -1245,12 +1304,25 @@ var ObjectMotionAnimation = class {
1245
1304
  if (!this.started || this.outroStart !== Infinity) return;
1246
1305
  this.outroPosition = this.motion.positionAt(now);
1247
1306
  this.outroVelocity = motionVectorAt(this.motion, now);
1248
- this.outroDirection = resolveDirection(this.outroVelocity, this.headings[0]);
1307
+ this.outroDirection = resolveDirection2(this.outroVelocity, this.headings[0]);
1249
1308
  this.outroStart = now;
1250
1309
  }
1251
1310
  isFinished() {
1252
1311
  return this.finished;
1253
1312
  }
1313
+ /** Milliseconds the fly-out takes; used to align a following particle trail's outro. */
1314
+ get outroDurationMs() {
1315
+ return this.outro.durationMs;
1316
+ }
1317
+ /**
1318
+ * A {@link MotionController} that follows the object's *actual* position, including
1319
+ * the intro fly-in and outro fly-out (it falls back to the raw motion path before
1320
+ * {@link enter} and once idle). Feed it to a particle layer's `emitter` so the
1321
+ * particles trail the object through its transitions instead of the bare path.
1322
+ */
1323
+ trailEmitter() {
1324
+ return { positionAt: (t) => this.sampleAt(t)?.position ?? this.motion.positionAt(t) };
1325
+ }
1254
1326
  render(now, frame) {
1255
1327
  if (!this.engine || !this.label) return;
1256
1328
  if (this.outroStart !== Infinity && now >= this.outroStart + this.outro.durationMs + this.tailCount * this.tailGap) {
@@ -1293,11 +1365,20 @@ var ObjectMotionAnimation = class {
1293
1365
  transform2.rotation.y = euler.y;
1294
1366
  transform2.rotation.z = euler.z;
1295
1367
  }
1296
- this.label.textContent = frame.indeterminate ? this.labelText ?? "" : `${Math.round(frame.progress * 100)}%`;
1368
+ this.label.setText(frame.indeterminate ? typeof this.labelContent === "string" ? this.labelContent : "" : `${Math.round(frame.progress * 100)}%`);
1369
+ if (this.fadeLabel) {
1370
+ this.label.setOpacity(animationLabelOpacity(
1371
+ now,
1372
+ this.started ? this.introStart : Infinity,
1373
+ this.intro.durationMs,
1374
+ this.outroStart,
1375
+ this.outro.durationMs
1376
+ ));
1377
+ }
1297
1378
  this.engine.render();
1298
1379
  }
1299
1380
  destroy() {
1300
- this.label?.remove();
1381
+ this.label?.container.remove();
1301
1382
  this.label = void 0;
1302
1383
  this.engine?.destroy();
1303
1384
  this.engine = void 0;
@@ -1330,7 +1411,7 @@ var ObjectMotionAnimation = class {
1330
1411
  const delta = transition.durationMs === 0 ? 1 : clamp012(elapsedMs / transition.durationMs);
1331
1412
  const input = this.transitionInput(phase, delta, elapsedMs, transition.durationMs, start);
1332
1413
  const output = transition.transition(input);
1333
- return this.applyTransitionOutput(input, output);
1414
+ return this.applyTransitionOutput(input, output, phase, t);
1334
1415
  }
1335
1416
  transitionInput(phase, delta, elapsedMs, durationMs, start) {
1336
1417
  if (phase === "intro") {
@@ -1339,7 +1420,7 @@ var ObjectMotionAnimation = class {
1339
1420
  return {
1340
1421
  delta,
1341
1422
  position: this.motion.positionAt(handoff),
1342
- direction: resolveDirection(velocity, { x: 1, y: 0, z: 0 }),
1423
+ direction: resolveDirection2(velocity, { x: 1, y: 0, z: 0 }),
1343
1424
  velocity,
1344
1425
  size: 1,
1345
1426
  durationMs,
@@ -1358,9 +1439,9 @@ var ObjectMotionAnimation = class {
1358
1439
  phase
1359
1440
  };
1360
1441
  }
1361
- applyTransitionOutput(input, output) {
1442
+ applyTransitionOutput(input, output, phase, t) {
1362
1443
  return {
1363
- position: output.position ?? input.position,
1444
+ position: output.position ?? (phase === "intro" ? this.motion.positionAt(t) : input.position),
1364
1445
  size: output.size ?? input.size ?? 1,
1365
1446
  orientation: output.orientation
1366
1447
  };