@phin-tech/dottie 0.1.0 → 0.3.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.
@@ -1,4 +1,4 @@
1
- /*! dottie.js 0.1.0 | Apache-2.0 | https://github.com/phin-tech/dottie */
1
+ /*! dottie.js 0.3.0 | Apache-2.0 | https://github.com/phin-tech/dottie */
2
2
  var __defProp = Object.defineProperty;
3
3
  var __defNormalProp = (obj, key, value2) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value: value2 }) : obj[key] = value2;
4
4
  var __export = (target, all) => {
@@ -16,6 +16,7 @@ __export(index_exports, {
16
16
  KINDS: () => KINDS,
17
17
  KNOWN_FIELDS: () => KNOWN_FIELDS,
18
18
  MAX_DURATION: () => MAX_DURATION,
19
+ MAX_MARCH: () => MAX_MARCH,
19
20
  Playback: () => Playback,
20
21
  SUPPORTED_VERSION: () => SUPPORTED_VERSION,
21
22
  VERSION: () => VERSION,
@@ -23,6 +24,7 @@ __export(index_exports, {
23
24
  bounds: () => bounds,
24
25
  cameraView: () => cameraView,
25
26
  clampFPS: () => clampFPS,
27
+ clampMarch: () => clampMarch,
26
28
  clampTime: () => clampTime,
27
29
  clear: () => clear,
28
30
  cloneElement: () => cloneElement,
@@ -59,13 +61,13 @@ __export(index_exports, {
59
61
  // src/model.ts
60
62
  var SUPPORTED_VERSION = 2;
61
63
  var KINDS = ["rectangle", "ellipse", "diamond", "text", "connector", "freehand", "path", "note", "image"];
62
- var EASES = ["linear", "easeIn", "easeOut", "easeInOut", "hold"];
64
+ var EASES = ["linear", "easeIn", "easeOut", "easeInOut", "hold", "spring", "bounce", "elastic"];
63
65
  var KNOWN_FIELDS = {
64
66
  file: ["version", "pages", "images"],
65
67
  page: ["id", "name", "layers", "elements", "theme", "guidesX", "guidesY", "guidesLocked", "timeline"],
66
68
  layer: ["id", "name", "visible", "locked"],
67
69
  rgba: ["r", "g", "b", "a"],
68
- style: ["stroke", "fill", "fillStyle", "strokeWidth", "dash", "roughness", "bowing", "fontSize", "gridSize", "opacity"],
70
+ style: ["stroke", "fill", "fillStyle", "strokeWidth", "dash", "roughness", "bowing", "fontSize", "gridSize", "opacity", "dashOffset"],
69
71
  element: [
70
72
  "id",
71
73
  "kind",
@@ -95,7 +97,7 @@ var KNOWN_FIELDS = {
95
97
  endpoint: ["elementID", "port", "x", "y"],
96
98
  connector: ["start", "end", "routing", "startHead", "endHead"],
97
99
  timeline: ["fps", "duration", "boil", "settle", "poster", "tracks", "camera", "markers"],
98
- track: ["element", "keys", "boil", "follow", "repeats"],
100
+ track: ["element", "keys", "boil", "follow", "repeats", "march"],
99
101
  keyframe: ["t", "x", "y", "width", "height", "rotation", "strokeWidth", "stroke", "fill", "visible", "reveal", "opacity", "ease"],
100
102
  follow: ["path", "start", "end", "ease", "reverse", "orient", "laps"],
101
103
  repeat: ["start", "end", "count"],
@@ -103,6 +105,8 @@ var KNOWN_FIELDS = {
103
105
  marker: ["t", "name"]
104
106
  };
105
107
  var MAX_DURATION = 3600;
108
+ var MAX_MARCH = 1e4;
109
+ var clampMarch = (v) => v === void 0 || !Number.isFinite(v) || v === 0 ? null : Math.min(Math.max(v, -MAX_MARCH), MAX_MARCH);
106
110
  var BOIL_DRAWINGS = 3;
107
111
  var black = { r: 0.12, g: 0.12, b: 0.13, a: 1 };
108
112
  var clear = { r: 0, g: 0, b: 0, a: 0 };
@@ -160,7 +164,8 @@ var Reader = class {
160
164
  bowing: num(s.bowing) ?? 1,
161
165
  fontSize: num(s.fontSize) ?? 18,
162
166
  gridSize: num(s.gridSize) ?? null,
163
- opacity: num(s.opacity) ?? null
167
+ opacity: num(s.opacity) ?? null,
168
+ dashOffset: num(s.dashOffset) ?? null
164
169
  };
165
170
  }
166
171
  endpoint(v) {
@@ -283,7 +288,7 @@ var Reader = class {
283
288
  const rep = { start, end, count: count === void 0 ? null : Math.trunc(count) };
284
289
  return repeatIsValid(rep) ? [rep] : [];
285
290
  }) : null;
286
- return { element, keys, boil: bool(v.boil) ?? null, follow, repeats };
291
+ return { element, keys, boil: bool(v.boil) ?? null, follow, repeats, march: clampMarch(num(v.march)) };
287
292
  }
288
293
  timeline(v) {
289
294
  if (!isObj(v)) return null;
@@ -2114,7 +2119,40 @@ function applyEase(ease, u) {
2114
2119
  return u < 0.5 ? 4 * u * u * u : 1 - Math.pow(-2 * u + 2, 3) / 2;
2115
2120
  case "hold":
2116
2121
  return 0;
2117
- }
2122
+ case "spring":
2123
+ return spring(u);
2124
+ case "bounce":
2125
+ return bounce(u);
2126
+ case "elastic":
2127
+ return elastic(u);
2128
+ }
2129
+ }
2130
+ function spring(u) {
2131
+ if (u <= 0) return 0;
2132
+ if (u >= 1) return 1;
2133
+ const s = (u2) => 1 - Math.exp(-6 * u2) * (Math.cos(3 * Math.PI * u2) + 6 / (3 * Math.PI) * Math.sin(3 * Math.PI * u2));
2134
+ return s(u) + u * (1 - s(1));
2135
+ }
2136
+ function bounce(u) {
2137
+ if (u <= 0) return 0;
2138
+ if (u >= 1) return 1;
2139
+ const n = 7.5625, d = 2.75;
2140
+ if (u < 1 / d) return n * u * u;
2141
+ if (u < 2 / d) {
2142
+ const v2 = u - 1.5 / d;
2143
+ return n * v2 * v2 + 0.75;
2144
+ }
2145
+ if (u < 2.5 / d) {
2146
+ const v2 = u - 2.25 / d;
2147
+ return n * v2 * v2 + 0.9375;
2148
+ }
2149
+ const v = u - 2.625 / d;
2150
+ return n * v * v + 0.984375;
2151
+ }
2152
+ function elastic(u) {
2153
+ if (u <= 0) return 0;
2154
+ if (u >= 1) return 1;
2155
+ return Math.pow(2, -10 * u) * Math.sin((u * 10 - 0.75) * (2 * Math.PI / 3)) + 1;
2118
2156
  }
2119
2157
  var rem = (a, b) => a % b;
2120
2158
  function localTime(track, t) {
@@ -2149,11 +2187,12 @@ function value(track, t, get, base, lerp) {
2149
2187
  return lerp(get(b), get(a), applyEase(b.ease ?? "linear", u));
2150
2188
  }
2151
2189
  var lerpNum = (a, b, u) => a + (b - a) * u;
2190
+ var mix01 = (a, b, u) => Math.min(Math.max(a + (b - a) * u, 0), 1);
2152
2191
  var lerpColor = (a, b, u) => ({
2153
- r: a.r + (b.r - a.r) * u,
2154
- g: a.g + (b.g - a.g) * u,
2155
- b: a.b + (b.b - a.b) * u,
2156
- a: a.a + (b.a - a.a) * u
2192
+ r: mix01(a.r, b.r, u),
2193
+ g: mix01(a.g, b.g, u),
2194
+ b: mix01(a.b, b.b, u),
2195
+ a: mix01(a.a, b.a, u)
2157
2196
  });
2158
2197
  function num2(track, t, p, base) {
2159
2198
  return value(track, t, (k) => k[p], base, lerpNum);
@@ -2191,10 +2230,10 @@ function applyTrack(track, e, t) {
2191
2230
  if (e.kind === "connector") return e;
2192
2231
  e.x = num2(track, t, "x", e.x);
2193
2232
  e.y = num2(track, t, "y", e.y);
2194
- e.width = num2(track, t, "width", e.width);
2195
- e.height = num2(track, t, "height", e.height);
2233
+ e.width = Math.max(0, num2(track, t, "width", e.width));
2234
+ e.height = Math.max(0, num2(track, t, "height", e.height));
2196
2235
  if (track.keys.some((k) => k.rotation !== void 0)) e.rotation = num2(track, t, "rotation", angle(e));
2197
- e.style.strokeWidth = num2(track, t, "strokeWidth", e.style.strokeWidth);
2236
+ e.style.strokeWidth = Math.max(0, num2(track, t, "strokeWidth", e.style.strokeWidth));
2198
2237
  e.style.stroke = value(track, t, (k) => k.stroke, e.style.stroke, lerpColor);
2199
2238
  e.style.fill = value(track, t, (k) => k.fill, e.style.fill, lerpColor);
2200
2239
  return e;
@@ -2223,7 +2262,7 @@ function following(track, e, t, page) {
2223
2262
  if (!pathElement || pathElement.id === e.id) return e;
2224
2263
  const line2 = tracing(pathElement, page);
2225
2264
  const span = f.end - f.start;
2226
- let u = applyEase(f.ease ?? "easeInOut", span > 0 ? Math.min(1, (t - f.start) / span) : 1) * (f.laps ?? 1);
2265
+ let u = Math.min(Math.max(applyEase(f.ease ?? "easeInOut", span > 0 ? Math.min(1, (t - f.start) / span) : 1), 0), 1) * (f.laps ?? 1);
2227
2266
  if (u > 1) u = rem(u, 1) === 0 ? 1 : rem(u, 1);
2228
2267
  if (f.reverse === true) u = 1 - u;
2229
2268
  const p = line2.point(u);
@@ -2237,6 +2276,16 @@ function following(track, e, t, page) {
2237
2276
  }
2238
2277
  return moved;
2239
2278
  }
2279
+ function marchOffset(tl, speed, period, t) {
2280
+ if (!(period > 0)) return 0;
2281
+ const d = clampTime(tl.duration);
2282
+ if (d > 0) {
2283
+ const laps = roundHalfAway(speed * d / period);
2284
+ if (laps !== 0) speed = laps * period / d;
2285
+ }
2286
+ const r = rem(speed * t, period);
2287
+ return r < 0 ? -r : r === 0 ? 0 : period - r;
2288
+ }
2240
2289
  function trackMap(tl) {
2241
2290
  const m = /* @__PURE__ */ new Map();
2242
2291
  for (const t of tl.tracks) if (!m.has(t.element)) m.set(t.element, t);
@@ -2269,6 +2318,11 @@ function resolved(page, t) {
2269
2318
  if (out === e) out = cloneElement(e);
2270
2319
  out.seed = boiled(e.seed, reseed);
2271
2320
  }
2321
+ const pattern = track?.march != null ? dashPattern(out.style.dash, out.style.strokeWidth) : null;
2322
+ if (track?.march != null && pattern) {
2323
+ if (out === e) out = cloneElement(e);
2324
+ out.style.dashOffset = marchOffset(timeline, track.march, pattern.reduce((a, b) => a + b, 0), t);
2325
+ }
2272
2326
  return out;
2273
2327
  });
2274
2328
  elements = elements.map((e, i) => hidden.has(e.id) ? page.elements[i] : e);
@@ -2311,7 +2365,7 @@ function cameraRect(tl, t) {
2311
2365
  if (!after) return rectOf(before);
2312
2366
  const u = applyEase(before.ease ?? "easeInOut", (t - before.t) / Math.max(after.t - before.t, 1e-9));
2313
2367
  const mix2 = (p, q) => p + (q - p) * u;
2314
- return { x: mix2(before.x, after.x), y: mix2(before.y, after.y), width: mix2(before.width, after.width), height: mix2(before.height, after.height) };
2368
+ return { x: mix2(before.x, after.x), y: mix2(before.y, after.y), width: Math.max(1, mix2(before.width, after.width)), height: Math.max(1, mix2(before.height, after.height)) };
2315
2369
  }
2316
2370
  var rectOf = (k) => ({ x: k.x, y: k.y, width: k.width, height: k.height });
2317
2371
  function cameraView(tl, t) {
@@ -2361,8 +2415,9 @@ function bounds(page, padding = 24) {
2361
2415
  return inset(rotatedBounds(e), -reach, -reach);
2362
2416
  };
2363
2417
  if (page.elements.length === 0) return { x: 0, y: 0, width: 200, height: 200 };
2418
+ const shown = page.elements.filter((e) => (e.style.opacity ?? 1) > 0);
2364
2419
  let r = null;
2365
- for (const e of page.elements) r = union(r, box(e));
2420
+ for (const e of shown.length ? shown : page.elements) r = union(r, box(e));
2366
2421
  return inset(r, -padding, -padding);
2367
2422
  }
2368
2423
  function plan(page) {
@@ -2446,6 +2501,7 @@ function svgElement(e, index, labelBackground) {
2446
2501
  let strokeAttrs = `stroke="${stroke}" stroke-width="${fmt(e.style.strokeWidth)}" stroke-linecap="round" stroke-linejoin="round"`;
2447
2502
  const dash = dashPattern(e.style.dash, e.style.strokeWidth);
2448
2503
  if (dash) strokeAttrs += ` stroke-dasharray="${dash.map(fmt).join(" ")}"`;
2504
+ if (dash && e.style.dashOffset !== null && fmt(e.style.dashOffset) !== "0") strokeAttrs += ` stroke-dashoffset="${fmt(e.style.dashOffset)}"`;
2449
2505
  let text = e.text;
2450
2506
  const r = revealProgress(e);
2451
2507
  if (r !== null) {
@@ -2976,6 +3032,7 @@ function inspectFrame(page, t) {
2976
3032
  if (e.rotation !== null) d.rotation = r4(e.rotation);
2977
3033
  if (e.style.opacity !== null) d.opacity = r4(e.style.opacity);
2978
3034
  if (e.reveal !== null) d.reveal = r4(e.reveal);
3035
+ if (e.style.dashOffset !== null) d.dashOffset = r4(e.style.dashOffset);
2979
3036
  d.strokeWidth = r4(e.style.strokeWidth);
2980
3037
  d.stroke = rgba2(e.style.stroke);
2981
3038
  d.fill = rgba2(e.style.fill);
@@ -3022,7 +3079,7 @@ function render(source, options = {}) {
3022
3079
  function isFile(v) {
3023
3080
  return typeof v === "object" && v !== null && Array.isArray(v.pages) && Array.isArray(v.warnings);
3024
3081
  }
3025
- var VERSION = "0.1.0";
3082
+ var VERSION = "0.3.0";
3026
3083
 
3027
3084
  // src/player-entry.ts
3028
3085
  definePlayer();
@@ -3034,6 +3091,7 @@ export {
3034
3091
  KINDS,
3035
3092
  KNOWN_FIELDS,
3036
3093
  MAX_DURATION,
3094
+ MAX_MARCH,
3037
3095
  Playback,
3038
3096
  SUPPORTED_VERSION,
3039
3097
  VERSION,
@@ -3041,6 +3099,7 @@ export {
3041
3099
  bounds,
3042
3100
  cameraView,
3043
3101
  clampFPS,
3102
+ clampMarch,
3044
3103
  clampTime,
3045
3104
  clear,
3046
3105
  cloneElement,