@ggterm/core 0.3.6 → 0.3.8

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-plot.js CHANGED
@@ -14641,6 +14641,8 @@ function handleServe(port) {
14641
14641
  }
14642
14642
  }
14643
14643
  }
14644
+ let lastNewPlotTime = 0;
14645
+ let lastBroadcastPlotId = null;
14644
14646
  const plotsDir = getPlotsDir();
14645
14647
  watch(plotsDir, (_event, filename) => {
14646
14648
  if (!filename || !filename.endsWith(".json"))
@@ -14648,42 +14650,31 @@ function handleServe(port) {
14648
14650
  if (debounceTimer)
14649
14651
  clearTimeout(debounceTimer);
14650
14652
  debounceTimer = setTimeout(() => {
14653
+ const latestId = getLatestPlotId();
14654
+ if (!latestId || latestId === lastBroadcastPlotId)
14655
+ return;
14656
+ lastBroadcastPlotId = latestId;
14657
+ lastNewPlotTime = Date.now();
14651
14658
  const payload = getLatestPayload();
14652
14659
  if (payload)
14653
14660
  broadcast(payload);
14654
14661
  }, 150);
14655
14662
  });
14656
14663
  let styleDebounce = null;
14657
- let lastStyleBroadcast = 0;
14658
14664
  watch(getGGTermDir(), (_event, filename) => {
14659
- if (filename !== "last-plot-vegalite.json" && filename !== "last-plot.json")
14665
+ if (filename !== "last-plot-vegalite.json")
14660
14666
  return;
14661
14667
  if (styleDebounce)
14662
14668
  clearTimeout(styleDebounce);
14663
14669
  styleDebounce = setTimeout(() => {
14664
- const now = Date.now();
14665
- if (now - lastStyleBroadcast < 500)
14670
+ if (Date.now() - lastNewPlotTime < 2000)
14671
+ return;
14672
+ const vegaLitePath = join3(getGGTermDir(), "last-plot-vegalite.json");
14673
+ if (!existsSync3(vegaLitePath))
14666
14674
  return;
14667
- lastStyleBroadcast = now;
14668
14675
  try {
14669
- let spec = null;
14676
+ const spec = JSON.parse(readFileSync3(vegaLitePath, "utf-8"));
14670
14677
  const latestId = getLatestPlotId();
14671
- if (filename === "last-plot.json") {
14672
- const plotPath = join3(getGGTermDir(), "last-plot.json");
14673
- if (!existsSync3(plotPath))
14674
- return;
14675
- const plot = JSON.parse(readFileSync3(plotPath, "utf-8"));
14676
- const geomTypes = plot._provenance?.geomTypes || [];
14677
- const hasCompositeMark = geomTypes.some((t) => COMPOSITE_MARKS.has(t));
14678
- spec = plotSpecToVegaLite(plot.spec, { interactive: !hasCompositeMark });
14679
- } else {
14680
- const vegaLitePath = join3(getGGTermDir(), "last-plot-vegalite.json");
14681
- if (!existsSync3(vegaLitePath))
14682
- return;
14683
- spec = JSON.parse(readFileSync3(vegaLitePath, "utf-8"));
14684
- }
14685
- if (!spec)
14686
- return;
14687
14678
  const provenance = {
14688
14679
  id: latestId || "styled",
14689
14680
  description: "Styled plot",
@@ -15103,6 +15094,14 @@ async function renderSpec(spec) {
15103
15094
  }
15104
15095
  }
15105
15096
 
15097
+ // Re-render on container resize so plot reflows correctly
15098
+ let resizeTimer = null;
15099
+ new ResizeObserver(() => {
15100
+ if (!view) return;
15101
+ if (resizeTimer) clearTimeout(resizeTimer);
15102
+ resizeTimer = setTimeout(() => { view.resize(); }, 150);
15103
+ }).observe(vis);
15104
+
15106
15105
  async function showPlot(data) {
15107
15106
  await renderSpec(data.spec);
15108
15107
  updateMeta(data.provenance);
@@ -15241,7 +15240,7 @@ import { join as join4 } from "path";
15241
15240
  // src/init.ts
15242
15241
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync2, existsSync as existsSync2, readdirSync as readdirSync2, statSync } from "fs";
15243
15242
  import { join as join2, extname } from "path";
15244
- var SKILLS_VERSION = "0.3.4";
15243
+ var SKILLS_VERSION = "0.3.7";
15245
15244
  var SKILLS = {
15246
15245
  "data-load": {
15247
15246
  files: {
@@ -15518,30 +15517,41 @@ allowed-tools: Read, Write, Bash(npx:*)
15518
15517
 
15519
15518
  Modify Vega-Lite specifications based on natural language requests.
15520
15519
 
15521
- ## Files
15520
+ ## CRITICAL: Which File to Edit
15521
+
15522
+ **ALWAYS read and write \`.ggterm/last-plot-vegalite.json\`** — this is the Vega-Lite spec that the viewer renders.
15522
15523
 
15523
- After creating a plot, these files exist:
15524
- - \`.ggterm/last-plot.json\` - Original PlotSpec
15525
- - \`.ggterm/last-plot-vegalite.json\` - Vega-Lite spec to modify
15524
+ **NEVER modify \`.ggterm/last-plot.json\`** that is the ggterm terminal format. Changes to it will NOT appear in the viewer.
15526
15525
 
15527
15526
  ## Common Customizations
15528
15527
 
15528
+ All examples below modify properties of the Vega-Lite spec read from \`.ggterm/last-plot-vegalite.json\`:
15529
+
15529
15530
  ### Title and Labels
15530
15531
 
15531
15532
  \`\`\`javascript
15532
15533
  spec.title = "New Title"
15534
+ spec.title = { text: "Title", subtitle: "Subtitle" }
15533
15535
  spec.encoding.x.title = "X Axis Label"
15534
15536
  spec.encoding.y.title = "Y Axis Label"
15537
+ spec.encoding.color.title = "Legend Title"
15535
15538
  \`\`\`
15536
15539
 
15537
15540
  ### Colors
15538
15541
 
15539
15542
  \`\`\`javascript
15540
- // Color scheme for categorical data
15541
- spec.encoding.color.scale = { scheme: "category10" }
15543
+ spec.encoding.color.scale = { scheme: "category10" } // categorical
15544
+ spec.encoding.color.scale = { scheme: "viridis" } // continuous
15545
+ spec.mark.color = "#3366cc" // single color
15546
+ \`\`\`
15542
15547
 
15543
- // Color scheme for continuous data
15544
- spec.encoding.color.scale = { scheme: "viridis" }
15548
+ ### Fonts and Config
15549
+
15550
+ \`\`\`javascript
15551
+ spec.config = spec.config || {}
15552
+ spec.config.font = "Helvetica"
15553
+ spec.config.title = { fontSize: 18, fontWeight: "bold" }
15554
+ spec.config.axis = { labelFontSize: 12, titleFontSize: 14 }
15545
15555
  \`\`\`
15546
15556
 
15547
15557
  ### Dimensions
@@ -15553,9 +15563,9 @@ spec.height = 400
15553
15563
 
15554
15564
  ## Workflow
15555
15565
 
15556
- 1. Read \`.ggterm/last-plot-vegalite.json\`
15557
- 2. Apply the requested modifications
15558
- 3. Write the updated spec back to \`.ggterm/last-plot-vegalite.json\`
15566
+ 1. Read \`.ggterm/last-plot-vegalite.json\` (NOT last-plot.json)
15567
+ 2. Parse as JSON, apply the requested modifications
15568
+ 3. Write the updated JSON back to \`.ggterm/last-plot-vegalite.json\`
15559
15569
  4. **DONE** — the live viewer auto-detects the change and displays the customized plot
15560
15570
 
15561
15571
  **IMPORTANT**: Do NOT re-create the plot with \`npx ggterm-plot\` after customizing. The viewer watches the spec file and auto-updates. Re-running the plot command would overwrite your customizations.
@@ -15576,26 +15586,107 @@ allowed-tools: Read, Write, Bash(npx:*)
15576
15586
 
15577
15587
  Apply expert-curated style presets to Vega-Lite specifications for publication-quality output.
15578
15588
 
15579
- ## Available Presets
15589
+ ## CRITICAL: Which File to Edit
15590
+
15591
+ **ALWAYS read and write \`.ggterm/last-plot-vegalite.json\`** — this is the Vega-Lite spec that the viewer renders.
15580
15592
 
15581
- | Preset | Inspiration | Key Characteristics |
15582
- |--------|-------------|---------------------|
15583
- | \`wilke\` | Claus Wilke's *Fundamentals of Data Visualization* | Minimal, clean, no chartjunk, subtle gridlines |
15584
- | \`tufte\` | Edward Tufte's data-ink ratio principles | Maximum data-ink, no grid, no borders |
15585
- | \`nature\` | Nature journal style | Clean, serif fonts, specific dimensions |
15586
- | \`economist\` | The Economist charts | Bold colors, distinctive style |
15587
- | \`minimal\` | Generic minimal style | No grid, no borders, clean |
15588
- | \`apa\` | APA publication guidelines | Academic papers, grayscale-friendly |
15593
+ **NEVER modify \`.ggterm/last-plot.json\`** that is the ggterm terminal format. Changes to it will NOT appear in the viewer.
15589
15594
 
15590
15595
  ## Workflow
15591
15596
 
15592
- 1. Read \`.ggterm/last-plot-vegalite.json\`
15593
- 2. Apply the requested style preset (only modify \`config\` — do NOT change \`encoding\`, \`data\`, or \`mark\` structure)
15594
- 3. Write the updated spec back to \`.ggterm/last-plot-vegalite.json\`
15595
- 4. **DONE** the live viewer auto-detects the change and displays the styled plot
15596
- 5. Inform user they can export with \`/ggterm-publish\`
15597
+ 1. Read \`.ggterm/last-plot-vegalite.json\` (NOT last-plot.json)
15598
+ 2. Parse as JSON
15599
+ 3. Set \`spec.config\` to the style config below do NOT change \`encoding\`, \`data\`, or \`mark\`
15600
+ 4. Write the updated JSON back to \`.ggterm/last-plot-vegalite.json\`
15601
+ 5. **DONE** the live viewer auto-detects the change and displays the styled plot
15602
+
15603
+ **IMPORTANT**: Do NOT re-create the plot with \`npx ggterm-plot\` after styling. Re-running would overwrite your style changes.
15604
+
15605
+ ## Style Configs (Vega-Lite \`config\` property)
15606
+
15607
+ ### Wilke (default for "publication ready")
15608
+
15609
+ \`\`\`json
15610
+ {
15611
+ "font": "Helvetica Neue, Helvetica, Arial, sans-serif",
15612
+ "background": "white",
15613
+ "view": { "stroke": null },
15614
+ "title": { "fontSize": 14, "fontWeight": "normal", "anchor": "start", "offset": 12 },
15615
+ "axis": { "domain": true, "domainColor": "#333333", "domainWidth": 1, "grid": false, "labelColor": "#333333", "labelFontSize": 11, "tickColor": "#333333", "tickSize": 5, "titleColor": "#333333", "titleFontSize": 12, "titleFontWeight": "normal", "titlePadding": 10 },
15616
+ "axisY": { "grid": true, "gridColor": "#ebebeb", "gridWidth": 0.5 },
15617
+ "legend": { "labelFontSize": 11, "titleFontSize": 11, "titleFontWeight": "normal", "symbolSize": 100 },
15618
+ "range": { "category": ["#4C78A8", "#F58518", "#E45756", "#72B7B2", "#54A24B", "#EECA3B", "#B279A2", "#FF9DA6"] }
15619
+ }
15620
+ \`\`\`
15621
+
15622
+ ### Tufte
15623
+
15624
+ \`\`\`json
15625
+ {
15626
+ "font": "Georgia, serif",
15627
+ "background": "white",
15628
+ "view": { "stroke": null },
15629
+ "title": { "fontSize": 13, "fontWeight": "normal", "anchor": "start" },
15630
+ "axis": { "domain": false, "grid": false, "labelColor": "#333333", "labelFontSize": 10, "ticks": false, "titleColor": "#333333", "titleFontSize": 11, "titleFontWeight": "normal" },
15631
+ "legend": { "labelFontSize": 10, "titleFontSize": 10, "titleFontWeight": "normal" },
15632
+ "range": { "category": ["#333333", "#666666", "#999999", "#CCCCCC"] }
15633
+ }
15634
+ \`\`\`
15635
+
15636
+ ### Nature
15597
15637
 
15598
- **IMPORTANT**: Do NOT re-create the plot with \`npx ggterm-plot\` after styling. The viewer watches the spec file and auto-updates. Re-running the plot command would overwrite your style changes.
15638
+ \`\`\`json
15639
+ {
15640
+ "font": "Arial, Helvetica, sans-serif",
15641
+ "background": "white",
15642
+ "view": { "stroke": null },
15643
+ "title": { "fontSize": 10, "fontWeight": "bold" },
15644
+ "axis": { "domain": true, "domainColor": "#000000", "domainWidth": 0.5, "grid": false, "labelColor": "#000000", "labelFontSize": 8, "tickColor": "#000000", "tickSize": 4, "tickWidth": 0.5, "titleColor": "#000000", "titleFontSize": 9, "titleFontWeight": "normal" },
15645
+ "legend": { "labelFontSize": 8, "titleFontSize": 8, "symbolSize": 50 }
15646
+ }
15647
+ \`\`\`
15648
+
15649
+ ### Economist
15650
+
15651
+ \`\`\`json
15652
+ {
15653
+ "font": "Officina Sans, Arial, sans-serif",
15654
+ "background": "#d5e4eb",
15655
+ "view": { "stroke": null },
15656
+ "title": { "fontSize": 14, "fontWeight": "bold", "color": "#000000", "anchor": "start" },
15657
+ "axis": { "domain": false, "grid": true, "gridColor": "#ffffff", "gridWidth": 1, "labelColor": "#000000", "labelFontSize": 11, "titleFontSize": 12, "titleFontWeight": "bold" },
15658
+ "axisX": { "grid": false, "domain": true, "domainColor": "#000000" },
15659
+ "legend": { "orient": "top", "labelFontSize": 11, "titleFontSize": 11 },
15660
+ "range": { "category": ["#006BA2", "#3EBCD2", "#379A8B", "#EBB434", "#B4BA39", "#9A607F", "#D73F3F"] }
15661
+ }
15662
+ \`\`\`
15663
+
15664
+ ### Minimal
15665
+
15666
+ \`\`\`json
15667
+ {
15668
+ "font": "system-ui, -apple-system, sans-serif",
15669
+ "background": "white",
15670
+ "view": { "stroke": null },
15671
+ "title": { "fontSize": 14, "fontWeight": "normal" },
15672
+ "axis": { "domain": false, "grid": false, "ticks": false, "labelColor": "#666666", "labelFontSize": 11, "titleColor": "#333333", "titleFontSize": 12, "titleFontWeight": "normal" },
15673
+ "legend": { "labelFontSize": 11, "titleFontSize": 11, "titleFontWeight": "normal" }
15674
+ }
15675
+ \`\`\`
15676
+
15677
+ ### APA
15678
+
15679
+ \`\`\`json
15680
+ {
15681
+ "font": "Times New Roman, serif",
15682
+ "background": "white",
15683
+ "view": { "stroke": null },
15684
+ "title": { "fontSize": 12, "fontWeight": "bold", "anchor": "middle" },
15685
+ "axis": { "domain": true, "domainColor": "#000000", "grid": false, "labelColor": "#000000", "labelFontSize": 10, "tickColor": "#000000", "titleColor": "#000000", "titleFontSize": 11, "titleFontWeight": "normal", "titleFontStyle": "italic" },
15686
+ "legend": { "labelFontSize": 10, "titleFontSize": 10, "titleFontStyle": "italic" },
15687
+ "range": { "category": ["#000000", "#666666", "#999999", "#CCCCCC"] }
15688
+ }
15689
+ \`\`\`
15599
15690
 
15600
15691
  ## Response Format
15601
15692
 
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAsgBH,wBAAgB,UAAU,IAAI,IAAI,CA2JjC"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAkmBH,wBAAgB,UAAU,IAAI,IAAI,CA2JjC"}
@@ -1 +1 @@
1
- {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAgfH,wBAAgB,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CA+J/C"}
1
+ {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAwfH,wBAAgB,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAqJ/C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ggterm/core",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "description": "Grammar of Graphics engine for terminals",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",