@miao-vision/cli 0.1.9 → 0.1.10

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/cli.cjs CHANGED
@@ -41719,7 +41719,19 @@ var defaultTheme = {
41719
41719
  labelColor: "#475569"
41720
41720
  },
41721
41721
  css: `
41722
- :root { color-scheme: light; font-family: Inter, ui-sans-serif, system-ui, -apple-system, sans-serif; }
41722
+ :root {
41723
+ color-scheme: light;
41724
+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, sans-serif;
41725
+ --mv-paper: #f8fafc;
41726
+ --mv-surface: #ffffff;
41727
+ --mv-border: #e2e8f0;
41728
+ --mv-ink: #0f172a;
41729
+ --mv-muted: #64748b;
41730
+ --mv-soft: #475569;
41731
+ --mv-brand: #2563eb;
41732
+ --mv-serif: Georgia, "Times New Roman", serif;
41733
+ --mv-mono: "SF Mono", "JetBrains Mono", Consolas, monospace;
41734
+ }
41723
41735
  body { margin: 0; background: #f8fafc; color: #0f172a; }
41724
41736
  .miao-viz-report { max-width: 1120px; margin: 0 auto; padding: 40px 24px 56px; }
41725
41737
  header { margin-bottom: 28px; }
@@ -41760,6 +41772,7 @@ var editorialTheme = {
41760
41772
  --mv-ink: #141413;
41761
41773
  --mv-muted: #6b6a64;
41762
41774
  --mv-soft-text: #504e49;
41775
+ --mv-soft: #504e49;
41763
41776
  --mv-brand: #1b365d;
41764
41777
  --mv-mono: "SF Mono", "JetBrains Mono", Consolas, monospace;
41765
41778
  --mv-serif: Charter, Georgia, "Times New Roman", serif;
@@ -41824,6 +41837,7 @@ var darkTheme = {
41824
41837
  --mv-ink: #e2e0d8;
41825
41838
  --mv-muted: #737069;
41826
41839
  --mv-soft-text: #a8a69f;
41840
+ --mv-soft: #a8a69f;
41827
41841
  --mv-brand: #7eb8f7;
41828
41842
  --mv-mono: "SF Mono", "JetBrains Mono", Consolas, monospace;
41829
41843
  --mv-serif: Charter, Georgia, "Times New Roman", serif;
@@ -41881,7 +41895,19 @@ var minimalTheme = {
41881
41895
  labelColor: "#6b7280"
41882
41896
  },
41883
41897
  css: `
41884
- :root { color-scheme: light; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; }
41898
+ :root {
41899
+ color-scheme: light;
41900
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
41901
+ --mv-paper: #ffffff;
41902
+ --mv-surface: #ffffff;
41903
+ --mv-border: #e5e7eb;
41904
+ --mv-ink: #111111;
41905
+ --mv-muted: #6b7280;
41906
+ --mv-soft: #374151;
41907
+ --mv-brand: #1d4ed8;
41908
+ --mv-serif: Georgia, "Times New Roman", serif;
41909
+ --mv-mono: "SF Mono", "JetBrains Mono", Consolas, monospace;
41910
+ }
41885
41911
  body { margin: 0; background: #fff; color: #111; }
41886
41912
  .miao-viz-report { max-width: 960px; margin: 0 auto; padding: 48px 24px 64px; }
41887
41913
  header { margin-bottom: 32px; }
@@ -58128,6 +58154,42 @@ function parseAnalyzeContext(value) {
58128
58154
  function withSize(chart, width, height) {
58129
58155
  return { ...chart, style: { ...chart.style, width, height } };
58130
58156
  }
58157
+ function formatMetricValue(num, fmt) {
58158
+ const hasCurrency = fmt.includes("$");
58159
+ const hasPercent = fmt.includes("%");
58160
+ const hasThousands = fmt.includes(",");
58161
+ const hasSiPrefix = fmt.includes("s");
58162
+ const precisionMatch = fmt.match(/\.(\d+)/);
58163
+ let precision = precisionMatch ? parseInt(precisionMatch[1], 10) : void 0;
58164
+ let value = num;
58165
+ let suffix = "";
58166
+ if (hasPercent) {
58167
+ value = num < 2 ? num * 100 : num;
58168
+ suffix = "%";
58169
+ if (precision === void 0) precision = 1;
58170
+ }
58171
+ if (hasSiPrefix) {
58172
+ const abs = Math.abs(value);
58173
+ if (abs >= 1e9) {
58174
+ value /= 1e9;
58175
+ suffix = "B" + suffix;
58176
+ } else if (abs >= 1e6) {
58177
+ value /= 1e6;
58178
+ suffix = "M" + suffix;
58179
+ } else if (abs >= 1e3) {
58180
+ value /= 1e3;
58181
+ suffix = "K" + suffix;
58182
+ }
58183
+ if (precision === void 0) precision = 0;
58184
+ }
58185
+ if (precision === void 0 && hasThousands) precision = 0;
58186
+ const fixed = precision !== void 0 ? value.toFixed(precision) : Math.round(value).toString();
58187
+ const [intPart, decPart] = fixed.split(".");
58188
+ const formattedInt = hasThousands ? intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : intPart;
58189
+ const formatted = decPart !== void 0 ? `${formattedInt}.${decPart}` : formattedInt;
58190
+ const prefix = hasCurrency ? "$" : "";
58191
+ return prefix + formatted + suffix;
58192
+ }
58131
58193
  function resolveMetricValue(metric, rows) {
58132
58194
  let raw = metric.value;
58133
58195
  if (raw === void 0 && metric.data?.transform?.length) {
@@ -58137,10 +58199,7 @@ function resolveMetricValue(metric, rows) {
58137
58199
  }
58138
58200
  const num = Number(raw);
58139
58201
  if (!Number.isFinite(num)) return String(raw ?? "\u2014");
58140
- const fmt = metric.format ?? "";
58141
- if (fmt.includes("$")) return "$" + Math.round(num).toLocaleString();
58142
- if (fmt.includes("%")) return (num < 2 ? (num * 100).toFixed(1) : num.toFixed(1)) + "%";
58143
- return Math.round(num).toLocaleString();
58202
+ return formatMetricValue(num, metric.format ?? "");
58144
58203
  }
58145
58204
  function renderEyebrow(text) {
58146
58205
  return `<div class="slide-eyebrow">${escapeHtml(text)}</div>`;
@@ -58166,21 +58225,22 @@ function pageFooter(index, _total, mark) {
58166
58225
  <div class="slide-page-num">${String(index + 1).padStart(2, "0")}</div>`;
58167
58226
  }
58168
58227
  var COVER_DECO = `<svg viewBox="0 0 320 320" xmlns="http://www.w3.org/2000/svg" style="width:260px;opacity:0.9">
58169
- <circle cx="160" cy="160" r="140" fill="none" stroke="#e5e3d8" stroke-width="1"/>
58170
- <circle cx="160" cy="160" r="100" fill="none" stroke="#e5e3d8" stroke-width="1"/>
58171
- <circle cx="160" cy="160" r="60" fill="#eef2f7" stroke="#1b365d" stroke-width="1.2"/>
58172
- <path d="M160 20 A140 140 0 0 1 300 160" fill="none" stroke="#1b365d" stroke-width="2.2" stroke-linecap="round"/>
58173
- <path d="M300 160 A140 140 0 0 1 160 300" fill="none" stroke="#6b6a64" stroke-width="1" stroke-linecap="round"/>
58174
- <path d="M160 300 A140 140 0 0 1 20 160" fill="none" stroke="#6b6a64" stroke-width="1" stroke-linecap="round"/>
58175
- <path d="M20 160 A140 140 0 0 1 160 20" fill="none" stroke="#6b6a64" stroke-width="1" stroke-linecap="round"/>
58228
+ <circle cx="160" cy="160" r="140" fill="none" stroke="var(--mv-border, #e5e3d8)" stroke-width="1"/>
58229
+ <circle cx="160" cy="160" r="100" fill="none" stroke="var(--mv-border, #e5e3d8)" stroke-width="1"/>
58230
+ <circle cx="160" cy="160" r="60" fill="var(--mv-surface, #eef2f7)" stroke="var(--mv-brand, #1b365d)" stroke-width="1.2"/>
58231
+ <path d="M160 20 A140 140 0 0 1 300 160" fill="none" stroke="var(--mv-brand, #1b365d)" stroke-width="2.2" stroke-linecap="round"/>
58232
+ <path d="M300 160 A140 140 0 0 1 160 300" fill="none" stroke="var(--mv-muted, #6b6a64)" stroke-width="1" stroke-linecap="round"/>
58233
+ <path d="M160 300 A140 140 0 0 1 20 160" fill="none" stroke="var(--mv-muted, #6b6a64)" stroke-width="1" stroke-linecap="round"/>
58234
+ <path d="M20 160 A140 140 0 0 1 160 20" fill="none" stroke="var(--mv-muted, #6b6a64)" stroke-width="1" stroke-linecap="round"/>
58176
58235
  </svg>`;
58177
- function renderCoverSlide(slide, _rows, _svg, index, total) {
58236
+ function renderCoverSlide(slide, _rows, _svg, index, total, deckDescription) {
58237
+ const subtitle = slide.claim ?? deckDescription;
58178
58238
  return `<div class="slide">
58179
58239
  <div class="slide-cover">
58180
58240
  <div class="slide-cover-left">
58181
58241
  <div class="slide-mark">miao-vision</div>
58182
58242
  <h1>${escapeHtml(slide.title ?? "Presentation")}</h1>
58183
- ${slide.claim ? `<div class="sub">${escapeHtml(slide.claim)}</div>` : ""}
58243
+ ${subtitle ? `<div class="sub">${escapeHtml(subtitle)}</div>` : ""}
58184
58244
  <div class="line"></div>
58185
58245
  <div class="meta">${escapeHtml(slide.eyebrow ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10))}</div>
58186
58246
  </div>
@@ -58266,18 +58326,6 @@ function renderEndingSlide(slide, _rows, _svg, index, total) {
58266
58326
 
58267
58327
  // src/deck-renderer.ts
58268
58328
  var SLIDE_CSS = `
58269
- :root {
58270
- --mv-paper: #f5f4ed;
58271
- --mv-surface: #faf9f5;
58272
- --mv-brand: #1b365d;
58273
- --mv-ink: #141413;
58274
- --mv-muted: #6b6a64;
58275
- --mv-soft: #504e49;
58276
- --mv-border: #e5e3d8;
58277
- --mv-serif: Charter, Georgia, "Times New Roman", serif;
58278
- --mv-mono: "SF Mono", "JetBrains Mono", Consolas, monospace;
58279
- --slide-scale: 1;
58280
- }
58281
58329
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
58282
58330
  body { font-family: var(--mv-serif); -webkit-font-smoothing: antialiased; }
58283
58331
 
@@ -58369,7 +58417,7 @@ var SLIDE_CSS = `
58369
58417
  .slide:last-child { break-after: auto; page-break-after: auto; }
58370
58418
  .slide-nav { display: none !important; }
58371
58419
  }
58372
- @page { size: A4 landscape; margin: 0; background: #f5f4ed; }
58420
+ @page { size: A4 landscape; margin: 0; background: var(--mv-paper, #f5f4ed); }
58373
58421
  `;
58374
58422
  var SLIDE_JS = `
58375
58423
  (function() {
@@ -58421,10 +58469,14 @@ var SLIDE_JS = `
58421
58469
  goTo(0);
58422
58470
  })();
58423
58471
  `;
58424
- function renderSlide(slide, rows, svgTheme, index, total) {
58472
+ function extractRootVars(css) {
58473
+ const match = css.match(/:root\s*\{([\s\S]*?)\}/);
58474
+ return match ? `:root {${match[1]}}` : "";
58475
+ }
58476
+ function renderSlide(slide, rows, svgTheme, index, total, deckDescription) {
58425
58477
  switch (slide.layout) {
58426
58478
  case "cover":
58427
- return renderCoverSlide(slide, rows, svgTheme, index, total);
58479
+ return renderCoverSlide(slide, rows, svgTheme, index, total, deckDescription);
58428
58480
  case "title-only":
58429
58481
  return renderTitleOnlySlide(slide, rows, svgTheme, index, total);
58430
58482
  case "text-points":
@@ -58443,16 +58495,19 @@ function renderSlide(slide, rows, svgTheme, index, total) {
58443
58495
  }
58444
58496
  function renderDeckHtml(spec, rows, themeOverride) {
58445
58497
  const theme = getTheme(themeOverride ?? spec.theme ?? "editorial");
58498
+ const themeRootVars = extractRootVars(theme.css);
58446
58499
  const title = spec.title ?? "Presentation";
58447
58500
  const total = spec.slides.length;
58448
- const slidesHtml = spec.slides.map((slide, i) => renderSlide(slide, rows, theme.svg, i, total)).join("\n");
58501
+ const slidesHtml = spec.slides.map((slide, i) => renderSlide(slide, rows, theme.svg, i, total, spec.description)).join("\n");
58449
58502
  return `<!doctype html>
58450
58503
  <html lang="en">
58451
58504
  <head>
58452
58505
  <meta charset="utf-8" />
58453
58506
  <meta name="viewport" content="width=device-width, initial-scale=1" />
58507
+ ${spec.description ? `<meta name="description" content="${escapeHtml(spec.description)}" />` : ""}
58454
58508
  <title>${escapeHtml(title)}</title>
58455
58509
  <style>${SLIDE_CSS}</style>
58510
+ ${themeRootVars ? `<style id="miao-deck-theme">${themeRootVars}</style>` : ""}
58456
58511
  </head>
58457
58512
  <body class="present-mode">
58458
58513
  <div class="slide-viewport">
@@ -58574,6 +58629,14 @@ function validateDeckSpecSemantics(spec) {
58574
58629
  hint: hintForIssue(path, "at most 4 metrics")
58575
58630
  });
58576
58631
  }
58632
+ if (slide.charts && slide.charts.length > 1) {
58633
+ const path = `slides[${index}].charts`;
58634
+ errors.push({
58635
+ path,
58636
+ message: `${path}: A slide can include at most 1 chart.`,
58637
+ hint: hintForIssue(path, "at most 1 chart")
58638
+ });
58639
+ }
58577
58640
  if (slide.layout === "table-full" && slide.charts?.[0] && slide.charts[0].type !== "table") {
58578
58641
  const path = `slides[${index}].charts[0].type`;
58579
58642
  errors.push({
@@ -58686,6 +58749,7 @@ function hintForIssue(path, message) {
58686
58749
  if (message.includes("requires at least one chart")) return `Add a chart under ${path}.`;
58687
58750
  if (message.includes("requires at least one metric")) return `Add one to four metrics under ${path}.`;
58688
58751
  if (message.includes("at most 4 metrics")) return `Reduce ${path} to four metrics or split them across multiple slides.`;
58752
+ if (message.includes("at most 1 chart")) return `Reduce ${path} to a single chart or spread multiple charts across separate slides.`;
58689
58753
  if (message.includes("only accepts a table chart")) return `Change ${path} to 'table' or use a chart-focused layout.`;
58690
58754
  return `Check ${path} in the DeckSpec.`;
58691
58755
  }
@@ -0,0 +1,33 @@
1
+ week,channel,impressions,clicks,conversions,spend
2
+ 2025-W01,Social,52000,2100,85,3400
3
+ 2025-W01,Search,38000,1850,72,2900
4
+ 2025-W01,Email,15000,980,45,1200
5
+ 2025-W01,Display,28000,620,18,2100
6
+ 2025-W02,Social,58000,2400,98,3600
7
+ 2025-W02,Search,42000,2100,84,3100
8
+ 2025-W02,Email,17000,1050,50,1250
9
+ 2025-W02,Display,31000,680,22,2200
10
+ 2025-W03,Social,65000,2750,112,3800
11
+ 2025-W03,Search,46000,2300,92,3200
12
+ 2025-W03,Email,19000,1120,55,1300
13
+ 2025-W03,Display,35000,750,26,2300
14
+ 2025-W04,Social,72000,3100,128,4000
15
+ 2025-W04,Search,51000,2500,101,3400
16
+ 2025-W04,Email,21000,1200,60,1400
17
+ 2025-W04,Display,38000,820,30,2400
18
+ 2025-W05,Social,68000,2900,118,3900
19
+ 2025-W05,Search,48000,2400,95,3300
20
+ 2025-W05,Email,20000,1150,57,1350
21
+ 2025-W05,Display,36000,790,28,2350
22
+ 2025-W06,Social,76000,3300,135,4200
23
+ 2025-W06,Search,54000,2650,108,3500
24
+ 2025-W06,Email,23000,1280,65,1450
25
+ 2025-W06,Display,40000,860,33,2500
26
+ 2025-W07,Social,81000,3550,148,4400
27
+ 2025-W07,Search,58000,2800,115,3600
28
+ 2025-W07,Email,25000,1350,70,1500
29
+ 2025-W07,Display,43000,910,36,2600
30
+ 2025-W08,Social,88000,3900,162,4600
31
+ 2025-W08,Search,62000,3000,125,3800
32
+ 2025-W08,Email,27000,1420,75,1550
33
+ 2025-W08,Display,46000,960,40,2700
@@ -0,0 +1,115 @@
1
+ title: Campaign Performance Report
2
+ theme: dark
3
+ slides:
4
+ - layout: cover
5
+ eyebrow: "2025 · Q1 Campaigns"
6
+ title: "Campaign Performance"
7
+ claim: "Social and Search channels drove 74% of conversions with improving efficiency."
8
+
9
+ - layout: metrics-chart
10
+ eyebrow: "01 · CAMPAIGN SNAPSHOT"
11
+ title: "Scale Improved While Efficiency Stayed Strong"
12
+ metrics:
13
+ - label: Total Impressions
14
+ format: ".0s"
15
+ data:
16
+ transform:
17
+ - type: aggregate
18
+ measures:
19
+ - field: impressions
20
+ op: sum
21
+ as: v
22
+ - label: Total Clicks
23
+ format: ".0s"
24
+ data:
25
+ transform:
26
+ - type: aggregate
27
+ measures:
28
+ - field: clicks
29
+ op: sum
30
+ as: v
31
+ - label: Total Spend
32
+ format: "$,.0f"
33
+ data:
34
+ transform:
35
+ - type: aggregate
36
+ measures:
37
+ - field: spend
38
+ op: sum
39
+ as: v
40
+ charts:
41
+ - type: line
42
+ title: Weekly Clicks
43
+ data:
44
+ transform:
45
+ - type: aggregate
46
+ groupBy: [week]
47
+ measures:
48
+ - field: clicks
49
+ op: sum
50
+ as: total
51
+ - type: sort
52
+ field: week
53
+ order: asc
54
+ encoding:
55
+ x: { field: week }
56
+ y: { field: total }
57
+
58
+ - layout: text-chart
59
+ eyebrow: "02 · CHANNEL EFFICIENCY"
60
+ title: "Social Scales While Email Converts"
61
+ annotation: "Social drives the most volume; Email has the best conversion rate per impression."
62
+ bullets:
63
+ - "Social: 41% of conversions, CPA trending down over the campaign."
64
+ - "Search: consistent volume with stable CPA."
65
+ - "Display: lowest CTR at 2.2%, but useful for top-of-funnel reach."
66
+ charts:
67
+ - type: scatter
68
+ title: Spend vs Conversions
69
+ data:
70
+ transform:
71
+ - type: aggregate
72
+ groupBy: [channel]
73
+ measures:
74
+ - field: spend
75
+ op: sum
76
+ as: total_spend
77
+ - field: conversions
78
+ op: sum
79
+ as: total_conversions
80
+ encoding:
81
+ x: { field: total_spend }
82
+ y: { field: total_conversions }
83
+
84
+ - layout: title-only
85
+ title: "03 · Channel Performance"
86
+
87
+ - layout: chart-full
88
+ eyebrow: "04 · DISTRIBUTION"
89
+ title: "Impression Distribution"
90
+ charts:
91
+ - type: histogram
92
+ title: Impression Distribution
93
+ encoding:
94
+ x: { field: impressions }
95
+
96
+ - layout: table-full
97
+ eyebrow: "05 · TOP CAMPAIGNS"
98
+ title: "Top Campaigns by Conversions"
99
+ charts:
100
+ - type: table
101
+ title: Top Campaigns
102
+ data:
103
+ transform:
104
+ - type: sort
105
+ field: conversions
106
+ order: desc
107
+ - type: limit
108
+ value: 10
109
+ encoding:
110
+ x: { field: channel }
111
+ y: { field: conversions }
112
+
113
+ - layout: ending
114
+ title: "Scale Social, protect Search, test Email retargeting"
115
+ claim: "Increase Social budget 15% and test Display retargeting in Q2."
@@ -0,0 +1,137 @@
1
+ title: Executive Overview
2
+ description: Revenue grew 22% QoQ driven by Alpha product adoption in East and South regions.
3
+ theme: editorial
4
+ slides:
5
+ - layout: cover
6
+ eyebrow: "2025 · Q1 Review"
7
+ title: "Executive Overview"
8
+ claim: "Revenue grew 22% QoQ driven by strong Enterprise product adoption."
9
+
10
+ - layout: title-only
11
+ title: "01 · Performance Highlights"
12
+
13
+ - layout: metrics-chart
14
+ eyebrow: "01 · PERFORMANCE HIGHLIGHTS"
15
+ title: "Revenue Growth Accelerated While Margins Held"
16
+ metrics:
17
+ - label: Total Revenue
18
+ format: "$,.0f"
19
+ data:
20
+ transform:
21
+ - type: aggregate
22
+ measures:
23
+ - field: revenue
24
+ op: sum
25
+ as: v
26
+ - label: Total Units
27
+ format: ",.0f"
28
+ data:
29
+ transform:
30
+ - type: aggregate
31
+ measures:
32
+ - field: units
33
+ op: sum
34
+ as: v
35
+ - label: Total Profit
36
+ format: "$,.0f"
37
+ data:
38
+ transform:
39
+ - type: aggregate
40
+ measures:
41
+ - field: profit
42
+ op: sum
43
+ as: v
44
+ - label: Avg Revenue
45
+ format: "$,.0f"
46
+ data:
47
+ transform:
48
+ - type: aggregate
49
+ measures:
50
+ - field: revenue
51
+ op: avg
52
+ as: v
53
+ charts:
54
+ - type: area
55
+ title: Monthly Revenue
56
+ data:
57
+ transform:
58
+ - type: derive-month
59
+ field: date
60
+ as: month
61
+ - type: aggregate
62
+ groupBy: [month]
63
+ measures:
64
+ - field: revenue
65
+ op: sum
66
+ as: total
67
+ - type: sort
68
+ field: month
69
+ order: asc
70
+ encoding:
71
+ x: { field: month }
72
+ y: { field: total }
73
+
74
+ - layout: text-points
75
+ eyebrow: "02 · KEY INSIGHTS"
76
+ title: "Revenue Drivers"
77
+ claim: "Three trends shaped the quarter: Enterprise expansion, regional balance, and product mix."
78
+ bullets:
79
+ - "Enterprise segment (Alpha + Gamma) contributed 68% of total revenue across all regions."
80
+ - "East region grew 29% QoQ, the fastest among all four regions."
81
+ - "Product Alpha leads with 42% revenue share, up from 40% in January."
82
+ callout: "Recommendation: Expand Alpha capacity in North region to capture untapped demand."
83
+
84
+ - layout: title-only
85
+ title: "02 · Revenue Breakdown"
86
+
87
+ - layout: text-chart
88
+ eyebrow: "03 · PRODUCT MIX"
89
+ title: "Product Revenue Is Concentrated in Alpha"
90
+ annotation: "Alpha is the top revenue product across every region."
91
+ bullets:
92
+ - "Alpha: 42% share, driven by Enterprise accounts."
93
+ - "Beta: 31% share, strongest in East and South."
94
+ - "Gamma: 27% share, growth opportunity in West."
95
+ charts:
96
+ - type: pie
97
+ title: Revenue by Product
98
+ data:
99
+ transform:
100
+ - type: aggregate
101
+ groupBy: [product]
102
+ measures:
103
+ - field: revenue
104
+ op: sum
105
+ as: total
106
+ - type: sort
107
+ field: total
108
+ order: desc
109
+ encoding:
110
+ label: { field: product }
111
+ value: { field: total }
112
+
113
+ - layout: chart-full
114
+ eyebrow: "04 · REGIONAL"
115
+ title: "Revenue by Region"
116
+ charts:
117
+ - type: bar
118
+ title: Revenue by Region
119
+ data:
120
+ transform:
121
+ - type: aggregate
122
+ groupBy: [region]
123
+ measures:
124
+ - field: revenue
125
+ op: sum
126
+ as: total
127
+ - type: sort
128
+ field: total
129
+ order: desc
130
+ encoding:
131
+ x: { field: region }
132
+ y: { field: total }
133
+ color: { field: region }
134
+
135
+ - layout: ending
136
+ title: "Focus on North region growth"
137
+ claim: "Enterprise product expansion in North is the highest-ROI opportunity for Q2."
@@ -0,0 +1,37 @@
1
+ date,region,product,segment,revenue,units,cost,profit
2
+ 2025-01-01,East,Alpha,Enterprise,45000,120,28000,17000
3
+ 2025-01-01,East,Beta,SMB,32000,85,21000,11000
4
+ 2025-01-01,East,Gamma,Enterprise,28000,70,19000,9000
5
+ 2025-01-01,West,Alpha,Enterprise,38000,100,25000,13000
6
+ 2025-01-01,West,Beta,SMB,29000,78,20000,9000
7
+ 2025-01-01,West,Gamma,Enterprise,22000,55,16000,6000
8
+ 2025-01-01,North,Alpha,Enterprise,31000,82,21000,10000
9
+ 2025-01-01,North,Beta,SMB,24000,65,17000,7000
10
+ 2025-01-01,North,Gamma,Enterprise,18000,48,13000,5000
11
+ 2025-01-01,South,Alpha,Enterprise,35000,92,23000,12000
12
+ 2025-01-01,South,Beta,SMB,26000,70,18000,8000
13
+ 2025-01-01,South,Gamma,Enterprise,20000,52,14000,6000
14
+ 2025-02-01,East,Alpha,Enterprise,51000,135,31000,20000
15
+ 2025-02-01,East,Beta,SMB,36000,95,23000,13000
16
+ 2025-02-01,East,Gamma,Enterprise,32000,80,21000,11000
17
+ 2025-02-01,West,Alpha,Enterprise,42000,110,27000,15000
18
+ 2025-02-01,West,Beta,SMB,32000,86,22000,10000
19
+ 2025-02-01,West,Gamma,Enterprise,25000,62,18000,7000
20
+ 2025-02-01,North,Alpha,Enterprise,35000,92,23000,12000
21
+ 2025-02-01,North,Beta,SMB,27000,72,19000,8000
22
+ 2025-02-01,North,Gamma,Enterprise,21000,55,15000,6000
23
+ 2025-02-01,South,Alpha,Enterprise,39000,102,25000,14000
24
+ 2025-02-01,South,Beta,SMB,29000,78,20000,9000
25
+ 2025-02-01,South,Gamma,Enterprise,23000,60,16000,7000
26
+ 2025-03-01,East,Alpha,Enterprise,58000,150,34000,24000
27
+ 2025-03-01,East,Beta,SMB,40000,105,25000,15000
28
+ 2025-03-01,East,Gamma,Enterprise,36000,90,23000,13000
29
+ 2025-03-01,West,Alpha,Enterprise,48000,125,30000,18000
30
+ 2025-03-01,West,Beta,SMB,36000,95,24000,12000
31
+ 2025-03-01,West,Gamma,Enterprise,29000,72,20000,9000
32
+ 2025-03-01,North,Alpha,Enterprise,40000,105,26000,14000
33
+ 2025-03-01,North,Beta,SMB,31000,82,21000,10000
34
+ 2025-03-01,North,Gamma,Enterprise,24000,62,17000,7000
35
+ 2025-03-01,South,Alpha,Enterprise,44000,115,28000,16000
36
+ 2025-03-01,South,Beta,SMB,33000,88,22000,11000
37
+ 2025-03-01,South,Gamma,Enterprise,26000,68,18000,8000
@@ -0,0 +1,33 @@
1
+ week,channel,impressions,clicks,conversions,spend
2
+ 2025-W01,Social,52000,2100,85,3400
3
+ 2025-W01,Search,38000,1850,72,2900
4
+ 2025-W01,Email,15000,980,45,1200
5
+ 2025-W01,Display,28000,620,18,2100
6
+ 2025-W02,Social,58000,2400,98,3600
7
+ 2025-W02,Search,42000,2100,84,3100
8
+ 2025-W02,Email,17000,1050,50,1250
9
+ 2025-W02,Display,31000,680,22,2200
10
+ 2025-W03,Social,65000,2750,112,3800
11
+ 2025-W03,Search,46000,2300,92,3200
12
+ 2025-W03,Email,19000,1120,55,1300
13
+ 2025-W03,Display,35000,750,26,2300
14
+ 2025-W04,Social,72000,3100,128,4000
15
+ 2025-W04,Search,51000,2500,101,3400
16
+ 2025-W04,Email,21000,1200,60,1400
17
+ 2025-W04,Display,38000,820,30,2400
18
+ 2025-W05,Social,68000,2900,118,3900
19
+ 2025-W05,Search,48000,2400,95,3300
20
+ 2025-W05,Email,20000,1150,57,1350
21
+ 2025-W05,Display,36000,790,28,2350
22
+ 2025-W06,Social,76000,3300,135,4200
23
+ 2025-W06,Search,54000,2650,108,3500
24
+ 2025-W06,Email,23000,1280,65,1450
25
+ 2025-W06,Display,40000,860,33,2500
26
+ 2025-W07,Social,81000,3550,148,4400
27
+ 2025-W07,Search,58000,2800,115,3600
28
+ 2025-W07,Email,25000,1350,70,1500
29
+ 2025-W07,Display,43000,910,36,2600
30
+ 2025-W08,Social,88000,3900,162,4600
31
+ 2025-W08,Search,62000,3000,125,3800
32
+ 2025-W08,Email,27000,1420,75,1550
33
+ 2025-W08,Display,46000,960,40,2700
@@ -0,0 +1,115 @@
1
+ title: Campaign Performance Report
2
+ theme: dark
3
+ slides:
4
+ - layout: cover
5
+ eyebrow: "2025 · Q1 Campaigns"
6
+ title: "Campaign Performance"
7
+ claim: "Social and Search channels drove 74% of conversions with improving efficiency."
8
+
9
+ - layout: metrics-chart
10
+ eyebrow: "01 · CAMPAIGN SNAPSHOT"
11
+ title: "Scale Improved While Efficiency Stayed Strong"
12
+ metrics:
13
+ - label: Total Impressions
14
+ format: ".0s"
15
+ data:
16
+ transform:
17
+ - type: aggregate
18
+ measures:
19
+ - field: impressions
20
+ op: sum
21
+ as: v
22
+ - label: Total Clicks
23
+ format: ".0s"
24
+ data:
25
+ transform:
26
+ - type: aggregate
27
+ measures:
28
+ - field: clicks
29
+ op: sum
30
+ as: v
31
+ - label: Total Spend
32
+ format: "$,.0f"
33
+ data:
34
+ transform:
35
+ - type: aggregate
36
+ measures:
37
+ - field: spend
38
+ op: sum
39
+ as: v
40
+ charts:
41
+ - type: line
42
+ title: Weekly Clicks
43
+ data:
44
+ transform:
45
+ - type: aggregate
46
+ groupBy: [week]
47
+ measures:
48
+ - field: clicks
49
+ op: sum
50
+ as: total
51
+ - type: sort
52
+ field: week
53
+ order: asc
54
+ encoding:
55
+ x: { field: week }
56
+ y: { field: total }
57
+
58
+ - layout: text-chart
59
+ eyebrow: "02 · CHANNEL EFFICIENCY"
60
+ title: "Social Scales While Email Converts"
61
+ annotation: "Social drives the most volume; Email has the best conversion rate per impression."
62
+ bullets:
63
+ - "Social: 41% of conversions, CPA trending down over the campaign."
64
+ - "Search: consistent volume with stable CPA."
65
+ - "Display: lowest CTR at 2.2%, but useful for top-of-funnel reach."
66
+ charts:
67
+ - type: scatter
68
+ title: Spend vs Conversions
69
+ data:
70
+ transform:
71
+ - type: aggregate
72
+ groupBy: [channel]
73
+ measures:
74
+ - field: spend
75
+ op: sum
76
+ as: total_spend
77
+ - field: conversions
78
+ op: sum
79
+ as: total_conversions
80
+ encoding:
81
+ x: { field: total_spend }
82
+ y: { field: total_conversions }
83
+
84
+ - layout: title-only
85
+ title: "03 · Channel Performance"
86
+
87
+ - layout: chart-full
88
+ eyebrow: "04 · DISTRIBUTION"
89
+ title: "Impression Distribution"
90
+ charts:
91
+ - type: histogram
92
+ title: Impression Distribution
93
+ encoding:
94
+ x: { field: impressions }
95
+
96
+ - layout: table-full
97
+ eyebrow: "05 · TOP CAMPAIGNS"
98
+ title: "Top Campaigns by Conversions"
99
+ charts:
100
+ - type: table
101
+ title: Top Campaigns
102
+ data:
103
+ transform:
104
+ - type: sort
105
+ field: conversions
106
+ order: desc
107
+ - type: limit
108
+ value: 10
109
+ encoding:
110
+ x: { field: channel }
111
+ y: { field: conversions }
112
+
113
+ - layout: ending
114
+ title: "Scale Social, protect Search, test Email retargeting"
115
+ claim: "Increase Social budget 15% and test Display retargeting in Q2."
@@ -0,0 +1,137 @@
1
+ title: Executive Overview
2
+ description: Revenue grew 22% QoQ driven by Alpha product adoption in East and South regions.
3
+ theme: editorial
4
+ slides:
5
+ - layout: cover
6
+ eyebrow: "2025 · Q1 Review"
7
+ title: "Executive Overview"
8
+ claim: "Revenue grew 22% QoQ driven by strong Enterprise product adoption."
9
+
10
+ - layout: title-only
11
+ title: "01 · Performance Highlights"
12
+
13
+ - layout: metrics-chart
14
+ eyebrow: "01 · PERFORMANCE HIGHLIGHTS"
15
+ title: "Revenue Growth Accelerated While Margins Held"
16
+ metrics:
17
+ - label: Total Revenue
18
+ format: "$,.0f"
19
+ data:
20
+ transform:
21
+ - type: aggregate
22
+ measures:
23
+ - field: revenue
24
+ op: sum
25
+ as: v
26
+ - label: Total Units
27
+ format: ",.0f"
28
+ data:
29
+ transform:
30
+ - type: aggregate
31
+ measures:
32
+ - field: units
33
+ op: sum
34
+ as: v
35
+ - label: Total Profit
36
+ format: "$,.0f"
37
+ data:
38
+ transform:
39
+ - type: aggregate
40
+ measures:
41
+ - field: profit
42
+ op: sum
43
+ as: v
44
+ - label: Avg Revenue
45
+ format: "$,.0f"
46
+ data:
47
+ transform:
48
+ - type: aggregate
49
+ measures:
50
+ - field: revenue
51
+ op: avg
52
+ as: v
53
+ charts:
54
+ - type: area
55
+ title: Monthly Revenue
56
+ data:
57
+ transform:
58
+ - type: derive-month
59
+ field: date
60
+ as: month
61
+ - type: aggregate
62
+ groupBy: [month]
63
+ measures:
64
+ - field: revenue
65
+ op: sum
66
+ as: total
67
+ - type: sort
68
+ field: month
69
+ order: asc
70
+ encoding:
71
+ x: { field: month }
72
+ y: { field: total }
73
+
74
+ - layout: text-points
75
+ eyebrow: "02 · KEY INSIGHTS"
76
+ title: "Revenue Drivers"
77
+ claim: "Three trends shaped the quarter: Enterprise expansion, regional balance, and product mix."
78
+ bullets:
79
+ - "Enterprise segment (Alpha + Gamma) contributed 68% of total revenue across all regions."
80
+ - "East region grew 29% QoQ, the fastest among all four regions."
81
+ - "Product Alpha leads with 42% revenue share, up from 40% in January."
82
+ callout: "Recommendation: Expand Alpha capacity in North region to capture untapped demand."
83
+
84
+ - layout: title-only
85
+ title: "02 · Revenue Breakdown"
86
+
87
+ - layout: text-chart
88
+ eyebrow: "03 · PRODUCT MIX"
89
+ title: "Product Revenue Is Concentrated in Alpha"
90
+ annotation: "Alpha is the top revenue product across every region."
91
+ bullets:
92
+ - "Alpha: 42% share, driven by Enterprise accounts."
93
+ - "Beta: 31% share, strongest in East and South."
94
+ - "Gamma: 27% share, growth opportunity in West."
95
+ charts:
96
+ - type: pie
97
+ title: Revenue by Product
98
+ data:
99
+ transform:
100
+ - type: aggregate
101
+ groupBy: [product]
102
+ measures:
103
+ - field: revenue
104
+ op: sum
105
+ as: total
106
+ - type: sort
107
+ field: total
108
+ order: desc
109
+ encoding:
110
+ label: { field: product }
111
+ value: { field: total }
112
+
113
+ - layout: chart-full
114
+ eyebrow: "04 · REGIONAL"
115
+ title: "Revenue by Region"
116
+ charts:
117
+ - type: bar
118
+ title: Revenue by Region
119
+ data:
120
+ transform:
121
+ - type: aggregate
122
+ groupBy: [region]
123
+ measures:
124
+ - field: revenue
125
+ op: sum
126
+ as: total
127
+ - type: sort
128
+ field: total
129
+ order: desc
130
+ encoding:
131
+ x: { field: region }
132
+ y: { field: total }
133
+ color: { field: region }
134
+
135
+ - layout: ending
136
+ title: "Focus on North region growth"
137
+ claim: "Enterprise product expansion in North is the highest-ROI opportunity for Q2."
@@ -0,0 +1,37 @@
1
+ date,region,product,segment,revenue,units,cost,profit
2
+ 2025-01-01,East,Alpha,Enterprise,45000,120,28000,17000
3
+ 2025-01-01,East,Beta,SMB,32000,85,21000,11000
4
+ 2025-01-01,East,Gamma,Enterprise,28000,70,19000,9000
5
+ 2025-01-01,West,Alpha,Enterprise,38000,100,25000,13000
6
+ 2025-01-01,West,Beta,SMB,29000,78,20000,9000
7
+ 2025-01-01,West,Gamma,Enterprise,22000,55,16000,6000
8
+ 2025-01-01,North,Alpha,Enterprise,31000,82,21000,10000
9
+ 2025-01-01,North,Beta,SMB,24000,65,17000,7000
10
+ 2025-01-01,North,Gamma,Enterprise,18000,48,13000,5000
11
+ 2025-01-01,South,Alpha,Enterprise,35000,92,23000,12000
12
+ 2025-01-01,South,Beta,SMB,26000,70,18000,8000
13
+ 2025-01-01,South,Gamma,Enterprise,20000,52,14000,6000
14
+ 2025-02-01,East,Alpha,Enterprise,51000,135,31000,20000
15
+ 2025-02-01,East,Beta,SMB,36000,95,23000,13000
16
+ 2025-02-01,East,Gamma,Enterprise,32000,80,21000,11000
17
+ 2025-02-01,West,Alpha,Enterprise,42000,110,27000,15000
18
+ 2025-02-01,West,Beta,SMB,32000,86,22000,10000
19
+ 2025-02-01,West,Gamma,Enterprise,25000,62,18000,7000
20
+ 2025-02-01,North,Alpha,Enterprise,35000,92,23000,12000
21
+ 2025-02-01,North,Beta,SMB,27000,72,19000,8000
22
+ 2025-02-01,North,Gamma,Enterprise,21000,55,15000,6000
23
+ 2025-02-01,South,Alpha,Enterprise,39000,102,25000,14000
24
+ 2025-02-01,South,Beta,SMB,29000,78,20000,9000
25
+ 2025-02-01,South,Gamma,Enterprise,23000,60,16000,7000
26
+ 2025-03-01,East,Alpha,Enterprise,58000,150,34000,24000
27
+ 2025-03-01,East,Beta,SMB,40000,105,25000,15000
28
+ 2025-03-01,East,Gamma,Enterprise,36000,90,23000,13000
29
+ 2025-03-01,West,Alpha,Enterprise,48000,125,30000,18000
30
+ 2025-03-01,West,Beta,SMB,36000,95,24000,12000
31
+ 2025-03-01,West,Gamma,Enterprise,29000,72,20000,9000
32
+ 2025-03-01,North,Alpha,Enterprise,40000,105,26000,14000
33
+ 2025-03-01,North,Beta,SMB,31000,82,21000,10000
34
+ 2025-03-01,North,Gamma,Enterprise,24000,62,17000,7000
35
+ 2025-03-01,South,Alpha,Enterprise,44000,115,28000,16000
36
+ 2025-03-01,South,Beta,SMB,33000,88,22000,11000
37
+ 2025-03-01,South,Gamma,Enterprise,26000,68,18000,8000
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miao-vision/cli",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Miao Vision local data visualization CLI for agent workflows",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,54 +0,0 @@
1
- title: Sales Dashboard
2
- description: Example Miao Vision report generated from sales.csv.
3
- charts:
4
- - type: bigvalue
5
- title: Total Sales
6
- data:
7
- transform:
8
- - type: aggregate
9
- measures:
10
- - field: sales
11
- op: sum
12
- as: total_sales
13
- encoding:
14
- value:
15
- field: total_sales
16
- - type: line
17
- title: Monthly Sales Trend
18
- data:
19
- transform:
20
- - type: derive-month
21
- field: order_date
22
- as: order_month
23
- - type: aggregate
24
- groupBy: [order_month]
25
- measures:
26
- - field: sales
27
- op: sum
28
- as: total_sales
29
- - type: sort
30
- field: order_month
31
- order: asc
32
- encoding:
33
- x:
34
- field: order_month
35
- y:
36
- field: total_sales
37
- - type: bar
38
- title: Sales by Region
39
- data:
40
- transform:
41
- - type: aggregate
42
- groupBy: [region]
43
- measures:
44
- - field: sales
45
- op: sum
46
- as: total_sales
47
- - type: sort
48
- field: total_sales
49
- order: desc
50
- encoding:
51
- x:
52
- field: region
53
- y:
54
- field: total_sales
@@ -1,54 +0,0 @@
1
- title: Sales Dashboard
2
- description: Example Miao Vision report generated from sales.csv.
3
- charts:
4
- - type: bigvalue
5
- title: Total Sales
6
- data:
7
- transform:
8
- - type: aggregate
9
- measures:
10
- - field: sales
11
- op: sum
12
- as: total_sales
13
- encoding:
14
- value:
15
- field: total_sales
16
- - type: line
17
- title: Monthly Sales Trend
18
- data:
19
- transform:
20
- - type: derive-month
21
- field: order_date
22
- as: order_month
23
- - type: aggregate
24
- groupBy: [order_month]
25
- measures:
26
- - field: sales
27
- op: sum
28
- as: total_sales
29
- - type: sort
30
- field: order_month
31
- order: asc
32
- encoding:
33
- x:
34
- field: order_month
35
- y:
36
- field: total_sales
37
- - type: bar
38
- title: Sales by Region
39
- data:
40
- transform:
41
- - type: aggregate
42
- groupBy: [region]
43
- measures:
44
- - field: sales
45
- op: sum
46
- as: total_sales
47
- - type: sort
48
- field: total_sales
49
- order: desc
50
- encoding:
51
- x:
52
- field: region
53
- y:
54
- field: total_sales