plotleaf 0.1.0 → 0.2.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/README.md +21 -2
- package/dist/assets/charts.js +17 -17
- package/dist/assets/styles.css +173 -0
- package/dist/cli.js +323 -17
- package/examples/onboarding/funnel.json +30 -0
- package/examples/onboarding/plans.json +14 -0
- package/examples/onboarding/report.md +42 -0
- package/examples/onboarding/signups.json +50 -0
- package/package.json +11 -1
- package/schema/components.json +135 -0
- package/skills/plotleaf/SKILL.md +14 -2
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: PLG Onboarding
|
|
3
|
+
description: A fictional product onboarding report with prepared funnel and plan data.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PLG Onboarding
|
|
7
|
+
|
|
8
|
+
A fictional product's onboarding performance, **6 April–28 June 2026**. All values and comparisons are synthetic, prepared by the example author.
|
|
9
|
+
|
|
10
|
+
:::grid{columns="4"}
|
|
11
|
+
::metric{label="Signups" value="12480" comparison="18.2% vs previous quarter" direction="up" sentiment="positive"}
|
|
12
|
+
::metric{label="Activated teams" value="7612" comparison="24.1% vs previous quarter" direction="up" sentiment="positive"}
|
|
13
|
+
::metric{label="Converted" value="1284" comparison="11.4% vs previous quarter" direction="up" sentiment="positive"}
|
|
14
|
+
::metric{label="Conversion rate" value="0.10288461538461538" format="percent" comparison="0.8 pt vs previous quarter" direction="up" sentiment="positive"}
|
|
15
|
+
:::
|
|
16
|
+
|
|
17
|
+
:::grid{columns="2"}
|
|
18
|
+
::area{data="./signups.json" x="week" y="signups" xType="date" title="Signups by week"}
|
|
19
|
+
::funnel{data="./funnel.json" stage="stage" value="teams" total="baseline" share="share" status="status" title="Funnel by stage"}
|
|
20
|
+
:::
|
|
21
|
+
|
|
22
|
+
## Activation mix
|
|
23
|
+
|
|
24
|
+
**7,612 teams** activated. Pro accounts for the largest share; each category below is mutually exclusive. Funnel percentages use **41,200 visitors** as the explicit denominator. The KPI conversion rate uses **12,480 signups**, so it answers a different question.
|
|
25
|
+
|
|
26
|
+
::::grid{columns="2"}
|
|
27
|
+
::donut{data="./plans.json" category="plan" value="teams" title="Activated teams by plan"}
|
|
28
|
+
:::table{data="./plans.json" title="Activated teams"}
|
|
29
|
+
::column{field="plan" label="Plan"}
|
|
30
|
+
::column{field="teams" label="Teams" format="number"}
|
|
31
|
+
:::
|
|
32
|
+
::::
|
|
33
|
+
|
|
34
|
+
### Key findings
|
|
35
|
+
|
|
36
|
+
- **Activation is the next opportunity.** Its below-target status is supplied by the author; the renderer does not infer it from the rate.
|
|
37
|
+
- **Conversion needs attention.** The author marked this stage at risk against the fictional team's own operating targets.
|
|
38
|
+
- **Pro leads the mix.** Plan counts add to the same 7,612 activated teams shown in the KPI and funnel.
|
|
39
|
+
|
|
40
|
+
:::callout{title="About this example"}
|
|
41
|
+
All data, comparisons, statuses and findings are fictional. This report has no live filters or data connections. The funnel preserves the prepared stage order and never guesses a denominator or business status.
|
|
42
|
+
:::
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"week": "2026-04-06",
|
|
4
|
+
"signups": 700
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
"week": "2026-04-13",
|
|
8
|
+
"signups": 800
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"week": "2026-04-20",
|
|
12
|
+
"signups": 770
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"week": "2026-04-27",
|
|
16
|
+
"signups": 850
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"week": "2026-05-04",
|
|
20
|
+
"signups": 980
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"week": "2026-05-11",
|
|
24
|
+
"signups": 1050
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"week": "2026-05-18",
|
|
28
|
+
"signups": 1040
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"week": "2026-05-25",
|
|
32
|
+
"signups": 1120
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"week": "2026-06-01",
|
|
36
|
+
"signups": 1180
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"week": "2026-06-08",
|
|
40
|
+
"signups": 1160
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"week": "2026-06-15",
|
|
44
|
+
"signups": 1230
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"week": "2026-06-22",
|
|
48
|
+
"signups": 1600
|
|
49
|
+
}
|
|
50
|
+
]
|
package/package.json
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plotleaf",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Beautiful, interactive reports from Markdown and JSON. Built for agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/LoueeD/plotleaf.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/LoueeD/plotleaf#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/LoueeD/plotleaf/issues"
|
|
14
|
+
},
|
|
7
15
|
"bin": {
|
|
8
16
|
"plotleaf": "./dist/cli.js"
|
|
9
17
|
},
|
|
@@ -22,6 +30,8 @@
|
|
|
22
30
|
"examples/storefront/*.json",
|
|
23
31
|
"examples/adoption/*.md",
|
|
24
32
|
"examples/adoption/*.json",
|
|
33
|
+
"examples/onboarding/*.md",
|
|
34
|
+
"examples/onboarding/*.json",
|
|
25
35
|
"skills/plotleaf/SKILL.md",
|
|
26
36
|
"README.md",
|
|
27
37
|
"LICENSE",
|
package/schema/components.json
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
"datasets": 64,
|
|
10
10
|
"rows": 100000,
|
|
11
11
|
"chartRows": 10000,
|
|
12
|
+
"donutSlices": 8,
|
|
13
|
+
"funnelStages": 20,
|
|
12
14
|
"tableRows": 1000,
|
|
13
15
|
"tableColumns": 40
|
|
14
16
|
},
|
|
@@ -32,6 +34,8 @@
|
|
|
32
34
|
"line",
|
|
33
35
|
"area",
|
|
34
36
|
"bar",
|
|
37
|
+
"donut",
|
|
38
|
+
"funnel",
|
|
35
39
|
"table",
|
|
36
40
|
"callout"
|
|
37
41
|
],
|
|
@@ -286,6 +290,135 @@
|
|
|
286
290
|
},
|
|
287
291
|
"example": "::bar{data=\"./errors.json\" x=\"category\" y=\"count\" title=\"Errors by category\"}"
|
|
288
292
|
},
|
|
293
|
+
"donut": {
|
|
294
|
+
"description": "A part-to-whole donut with a readable legend and native data table.",
|
|
295
|
+
"forms": [
|
|
296
|
+
"leaf"
|
|
297
|
+
],
|
|
298
|
+
"children": [],
|
|
299
|
+
"props": {
|
|
300
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
301
|
+
"type": "object",
|
|
302
|
+
"properties": {
|
|
303
|
+
"data": {
|
|
304
|
+
"type": "string",
|
|
305
|
+
"minLength": 1,
|
|
306
|
+
"maxLength": 1000
|
|
307
|
+
},
|
|
308
|
+
"category": {
|
|
309
|
+
"type": "string",
|
|
310
|
+
"minLength": 1,
|
|
311
|
+
"maxLength": 1000
|
|
312
|
+
},
|
|
313
|
+
"value": {
|
|
314
|
+
"type": "string",
|
|
315
|
+
"minLength": 1,
|
|
316
|
+
"maxLength": 1000
|
|
317
|
+
},
|
|
318
|
+
"title": {
|
|
319
|
+
"type": "string",
|
|
320
|
+
"minLength": 1,
|
|
321
|
+
"maxLength": 1000
|
|
322
|
+
},
|
|
323
|
+
"format": {
|
|
324
|
+
"default": "number",
|
|
325
|
+
"type": "string",
|
|
326
|
+
"pattern": "^(number|percent|percentage-points|currency:[A-Z]{3})$"
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
"required": [
|
|
330
|
+
"data",
|
|
331
|
+
"category",
|
|
332
|
+
"value",
|
|
333
|
+
"title",
|
|
334
|
+
"format"
|
|
335
|
+
],
|
|
336
|
+
"additionalProperties": false
|
|
337
|
+
},
|
|
338
|
+
"example": "::donut{data=\"./plans.json\" category=\"plan\" value=\"teams\" title=\"Teams by plan\"}",
|
|
339
|
+
"dataRules": {
|
|
340
|
+
"category": "Unique nonblank strings of at most 1000 characters; source order is preserved.",
|
|
341
|
+
"value": "Finite nonnegative numbers with a finite sum. Nulls and numeric strings are invalid. All-zero values show an empty state.",
|
|
342
|
+
"maximumRows": 8
|
|
343
|
+
}
|
|
344
|
+
},
|
|
345
|
+
"funnel": {
|
|
346
|
+
"description": "Ordered stage/progress rows with prepared values, denominators, shares and optional explicit status. Works without JavaScript.",
|
|
347
|
+
"forms": [
|
|
348
|
+
"leaf"
|
|
349
|
+
],
|
|
350
|
+
"children": [],
|
|
351
|
+
"props": {
|
|
352
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
353
|
+
"type": "object",
|
|
354
|
+
"properties": {
|
|
355
|
+
"data": {
|
|
356
|
+
"type": "string",
|
|
357
|
+
"minLength": 1,
|
|
358
|
+
"maxLength": 1000
|
|
359
|
+
},
|
|
360
|
+
"stage": {
|
|
361
|
+
"type": "string",
|
|
362
|
+
"minLength": 1,
|
|
363
|
+
"maxLength": 1000
|
|
364
|
+
},
|
|
365
|
+
"value": {
|
|
366
|
+
"type": "string",
|
|
367
|
+
"minLength": 1,
|
|
368
|
+
"maxLength": 1000
|
|
369
|
+
},
|
|
370
|
+
"total": {
|
|
371
|
+
"type": "string",
|
|
372
|
+
"minLength": 1,
|
|
373
|
+
"maxLength": 1000
|
|
374
|
+
},
|
|
375
|
+
"share": {
|
|
376
|
+
"type": "string",
|
|
377
|
+
"minLength": 1,
|
|
378
|
+
"maxLength": 1000
|
|
379
|
+
},
|
|
380
|
+
"status": {
|
|
381
|
+
"type": "string",
|
|
382
|
+
"minLength": 1,
|
|
383
|
+
"maxLength": 1000
|
|
384
|
+
},
|
|
385
|
+
"title": {
|
|
386
|
+
"type": "string",
|
|
387
|
+
"minLength": 1,
|
|
388
|
+
"maxLength": 1000
|
|
389
|
+
},
|
|
390
|
+
"format": {
|
|
391
|
+
"default": "number",
|
|
392
|
+
"type": "string",
|
|
393
|
+
"pattern": "^(number|percent|percentage-points|currency:[A-Z]{3})$"
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
"required": [
|
|
397
|
+
"data",
|
|
398
|
+
"stage",
|
|
399
|
+
"value",
|
|
400
|
+
"total",
|
|
401
|
+
"share",
|
|
402
|
+
"title",
|
|
403
|
+
"format"
|
|
404
|
+
],
|
|
405
|
+
"additionalProperties": false
|
|
406
|
+
},
|
|
407
|
+
"example": "::funnel{data=\"./funnel.json\" stage=\"stage\" value=\"teams\" total=\"baseline\" share=\"share\" status=\"status\" title=\"Funnel by stage\"}",
|
|
408
|
+
"dataRules": {
|
|
409
|
+
"stage": "Unique nonblank strings of at most 1000 characters; source order is preserved.",
|
|
410
|
+
"value": "Finite nonnegative number no greater than its row's total.",
|
|
411
|
+
"total": "Finite positive denominator supplied per row. No denominator is inferred from adjacent stages.",
|
|
412
|
+
"share": "Prepared ratio from 0 to 1, matching value / total to within 0.0005 (rounding to 0.1 percentage point).",
|
|
413
|
+
"status": [
|
|
414
|
+
"on-target",
|
|
415
|
+
"below-target",
|
|
416
|
+
"at-risk",
|
|
417
|
+
"neutral"
|
|
418
|
+
],
|
|
419
|
+
"maximumRows": 20
|
|
420
|
+
}
|
|
421
|
+
},
|
|
289
422
|
"table": {
|
|
290
423
|
"description": "A semantic sortable table, with inferred or explicitly formatted columns.",
|
|
291
424
|
"forms": [
|
|
@@ -411,6 +544,8 @@
|
|
|
411
544
|
"Dataset fields are literal own-property keys, not expressions.",
|
|
412
545
|
"Charts preserve source order; date/number x values must increase.",
|
|
413
546
|
"Line/area null y values create gaps; bar null y values are invalid.",
|
|
547
|
+
"Donut category/value fields must differ; category count is bounded, and all-zero values do not create equal slices.",
|
|
548
|
+
"Funnel fields must differ; shares and denominators are supplied, validated and displayed per row, with no sorting or status inference.",
|
|
414
549
|
"Filters, maps, images, nested data and executable components are not supported in this release."
|
|
415
550
|
]
|
|
416
551
|
}
|
package/skills/plotleaf/SKILL.md
CHANGED
|
@@ -11,9 +11,9 @@ Use an installed `plotleaf` CLI or `npx plotleaf`. In an unpublished source chec
|
|
|
11
11
|
|
|
12
12
|
## Discover the contract
|
|
13
13
|
|
|
14
|
-
Run `plotleaf schema` (or `npx plotleaf schema`) for the current machine-readable component/prop specifications, rules and input limits. Prefer that output over remembered syntax. Supported
|
|
14
|
+
Run `plotleaf schema` (or `npx plotleaf schema`) for the current machine-readable component/prop specifications, rules and input limits. Prefer that output over remembered syntax. Supported components in 0.2.0 include `grid`, `metric`, `line`, `area`, `bar`, `donut`, `funnel`, `table`, `column` and `callout`. Donut and funnel require plotleaf 0.2.0 or newer; check the installed CLI's schema when using an older version.
|
|
15
15
|
|
|
16
|
-
Use ordinary Markdown for headings, prose, findings, emphasis, lists, links and dividers. Headings provide sections. Design is built in; do not add custom CSS, raw HTML or framework components. Filters, maps,
|
|
16
|
+
Use ordinary Markdown for headings, prose, findings, emphasis, lists, links and dividers. Headings provide sections. Design is built in; do not add custom CSS, raw HTML or framework components. Filters, maps, image/sparkline cells and executable/custom components are future capabilities, not supported syntax.
|
|
17
17
|
|
|
18
18
|
## Author prepared content
|
|
19
19
|
|
|
@@ -51,6 +51,18 @@ Literal attributes are quoted strings, decoded by the component schema. `::` is
|
|
|
51
51
|
- Metrics, comparisons and business sentiment are supplied by the agent. An increase is not automatically positive. Comparison direction and sentiment are independent; both require comparison text when explicitly supplied. Numeric table changes can declare `higher-is-better` or `lower-is-better` semantics.
|
|
52
52
|
- Include data period, provenance and limitations in the prose where they help readers assess the report. Do not invent findings or imply filters/refresh that the file does not provide.
|
|
53
53
|
|
|
54
|
+
## Part-to-whole and stage views
|
|
55
|
+
|
|
56
|
+
```markdown
|
|
57
|
+
::donut{data="./plans.json" category="plan" value="teams" title="Teams by plan"}
|
|
58
|
+
::funnel{data="./funnel.json" stage="stage" value="teams" total="baseline" share="share" status="status" title="Funnel by stage"}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- Donuts require at most eight unique, nonblank string categories and finite nonnegative values with a finite sum. Prepare mutually exclusive parts of one whole; group a tail into an explicit Other row before rendering if appropriate. Zero values remain in the legend/data; all-zero data is an empty state, never equal slices.
|
|
62
|
+
- Funnel rows supply value, positive denominator and share explicitly, such as `{"stage":"Activated","teams":25,"baseline":100,"share":0.25,"status":"below-target"}`. Shares use ratios and must match value / total within 0.0005 (rounding to 0.1 percentage point). No baseline means an empty array, not a zero denominator.
|
|
63
|
+
- Funnel stage names are unique nonblank strings, with at most 20 stages in source order. Each stage can have its own denominator; explain that choice in prose. Status values are `on-target`, `below-target`, `at-risk` or `neutral`. Omit the status mapping for neutral styling; the engine never infers business status. All mapped fields must differ.
|
|
64
|
+
- Use the full-value data disclosures to check counts behind compact funnel labels. Both components retain readable HTML data without JavaScript. Keep the denominator of any nearby conversion KPI explicit when it differs from the funnel baseline.
|
|
65
|
+
|
|
54
66
|
## Validate, preview and export
|
|
55
67
|
|
|
56
68
|
```bash
|