CommunityWriting & Editinggithub.com

Lieflat Charts

A data visualization Skill for AI agents that transforms data into polished, interactive HTML charts.

What is Lieflat Charts?

Lieflat Charts is a data visualization skill for AI agents (like Claude Code, Cursor, or Codex) that generates beautiful, editorial-style HTML charts from raw data. It follows a strict template-first approach, using a library of over 50 chart templates organized into three families: Lupi Editorial (L1–L15), Lupi Basics (F1–F13), and Glance (G1–G18). The skill enforces a 'Mono' grayscale default with automatic color preset selection based on data semantics and context. It produces single-file HTML that can be opened directly in a browser without build tools, with data editable in a single array at the top of the file. The skill is designed for non-programmer end users (writers, marketers, PPT creators) who speak in plain language, not chart type names. It enforces strict rules on visual proportionality, typography, animation, and color usage, with a comprehensive self-check list for every deliverable. Supported platforms include moxt.ai for Lupi editorial storytelling, Glance for quick dashboards, Basics for foundational charts, and Interactive for large-scale data exploration.

Works with~Claude Code~Codex CLI~Cursor
npx skills add larashero3-dotcom/lieflat-charts

Installed? Explore more Writing & Editing skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Lieflat Charts — Chart Taste Codex

Lieflat Charts is a data visualization skill following the Agent Skills format, with Mono grayscale as the baseline. It also automatically selects a color preset when data semantics and usage context clearly call for it, focusing on turning data charts into visual content that has editorial feel, is readable, and forms a complete page. This skill is created at moxt.ai and supports Lupi editorial storytelling, Glance quick judgment, Basics foundational editing, and Interactive large charts. Given your data and context, you produce a single-file HTML that opens with a double-click and requires no build tools; editing data only requires modifying a single array at the top. Pure SVG charts run offline; charts using Chart.js, ECharts, or online fonts require internet if dependencies are not inlined. Default selection must start from Lupi Editorial and Lupi Basics; only use Glance if neither has a suitable template, or if the user explicitly requests Glance / dashboard / quick-read.

Color does not need to be triggered explicitly by the user. Follow section 6.5 to automatically decide between Mono and the three built-in presets in color-presets.js; if the user explicitly provides brand colors or custom color values, you may establish a custom palette for the deliverable. The same HTML or the same set of deliverables must lock to one color system; mixing is not allowed. Skin samples are in templates/color/.

How to find reference code for a chart: Look up the chart type in the catalog → open the corresponding gallery file → find the <div class="card"> block by the card's title to see the structure → search for the same // ════ comment block in <script> for the rendering code. Do not copy the entire page—galleries are multi-card pages; deliverables to users are always single-chart files assembled according to the Section 9 skeleton.

Target users are non-programmers (writers, operations people, PPT makers). They speak in plain language ("Help me draw this quarter's conversion for my public account post"), not chart type names. Your job is to translate plain language into the correct chart, one that looks good enough to be published directly.


Zero: Template-First Hard Constraints

The following rules are not suggestions; any violation requires rework:

  1. Must generate from repository templates. Each final chart first locks its chart type number in catalog.md, then opens the corresponding gallery for the real implementation: Lupi uses templates/lupi-gallery.html, Basics uses templates/basics-gallery.html, Glance uses templates/glance-gallery.html, Interactive large charts use templates/big-*.html. Colored charts still use these original templates as the structural source; templates/color/ is only for checking color schemes.
  2. Must follow the selected template's code skeleton. Start from the <div class="card"> block and the // ════ Chart Name ════ comment block corresponding to the card's title. Preserve the core SVG / Canvas / ECharts structure, data encoding method, proportional relationships, and animation rhythm. You may replace data, titles, annotations, sources, and necessary layout; you are prohibited from drawing a "looks similar" chart outside the template, from splicing multiple templates to create a hybrid chart type, or from falling back to chart library default styles.
  3. Default selection order is fixed. First fully compare Lupi Editorial (L1–L15), then Lupi Basics (F1–F13). If any template within these two groups can honestly carry the data, accommodate labels, and be readable, you must choose from these two groups.
  4. Glance is the default fallback, not a co-equal first choice. Only use Glance when Lupi Editorial and Lupi Basics are both unsuitable, or when the user explicitly requests Glance, dashboard, monitoring, weekly report, or a three-second quick read. Before downgrading, you must write down the specific reasons why Lupi / Basics are unsuitable.
  5. Creating new charts outside the library is a last resort. When Lupi, Basics, Glance, and Interactive templates all fail to carry the data, follow the translation process in Section 6; the new chart must still inherit the visual grammar and code structure of the closest gallery template.

One: Workflow (follow these six steps for every request)

  1. Judge the data shape. Don't ask the user what chart they want; look at what their data looks like: comparison of a few categories? Time series? Proportions? Positive and negative values? Many-to-one attribution? Network? Distribution of individual records? The shape is the key to selecting the chart.
  2. Audit Lupi and Basics first. Scan all candidate Lupi Editorial (L1–L15) and Lupi Basics (F1–F13) templates that can host the data shape. Compare at least 3 candidates; if fewer than 3, list all candidates. Compare semantic fit, honest units, label accommodation, reading speed, narrative tension, and whether this family has been used in the same batch.
  3. Check Glance only if necessary. Only scan Glance (G1–G18) when all Lupi and Basics candidates fail, or when the user explicitly requests Glance / dashboard / monitoring / weekly report / three-second quick read. When choosing Glance, record why Lupi and Basics cannot carry the data; do not just write "Glance is more intuitive."
  4. Lock the real template, then organize the page. Each chart must record the system, chart type number, gallery file, and card title, and use the real structure and rendering code of that card as the skeleton. Do not first think "I want to tell six things on this page" and then invent chart types on the fly; page narrative can only be organized after template selection.
  5. Form batches according to chart count rules. One chart carries one independent conclusion; after removing duplicate conclusions, determine the quantity according to the default ranges in Section 1.1. Templates must be assigned globally: no repetition, no stacking the same silhouette, no forcing extra charts just to fill numbers.
  6. Render from the template and self-check (Sections 0, 2, 3, 8). Check item by item whether the output still corresponds to the selected gallery implementation; changing data must not replace the template's core geometry, encoding, or animation. Choose Mono or one set of color presets for the entire deliverable according to Section 6.5; charts outside the library follow the translation process (Section 6).

1.1 Chart Count Rules

The number of charts is determined by the number of independent conclusions, not by "how many data columns there are," and is not fixed at 5 or 6 charts:

Request TypeDefault Output CountRules
Single question / single table / one metric1Deliver only the strongest chart; do not expand just to showcase templates
Two to three clear conclusions2–3Each chart carries a different conclusion; they may share the same data source
An article, paper, or complete case4–6Cover different data shapes: overview, composition, comparison, relationship, or change
User explicitly specifies a numberFollow user requestStill remove duplicate charts; if insufficient to support the request, explain and do fewer
  • The default maximum per page is 6 charts; more than 6 requires splitting into multiple pages or delivering by chapter.
  • Candidate alternatives, Glance/Lupi comparison drafts do not count toward the final chart count; they are part of the selection process, not the output batch.
  • Multi-chart pages must retain at least one overview conclusion; remaining charts must provide new comparison dimensions, relationships, temporal changes, or detailed evidence.
  • If two charts express the same conclusion, keep only the one more appropriate for the reading context and with a more honest data contract.

Two: Mono Syntax · Hard Rules (Violation Requires Rework)

Default reference is mono-tokens.js (inline the content into the HTML when distributing openly). Any value conflicting with a token must defer to the token. When using color, only replace the color tokens; fonts, rounding, layout, and animation still follow mono-tokens.js.

Colors

  • Default has only paper gray #F0EFEB and charcoal black #1C1C1A at the extremes, with 7 intermediate grayscale steps in between. Color exceptions start from presets per Section 6.5.
  • Brightness equals data: Most important = darkest (on dark cards, reversed to brightest). Multiple series are assigned along the ladder by importance, not taken arbitrarily in order.
  • Always solid: No transparency, no glow, no gradient filters, no shadows. Texture comes solely from brightness contrast and shape. The only exception: in superimposition charts (Radial Patchwork), transparency encodes density—that is data, not decoration.
  • Dark cards (.card.dark) are only for two types of charts: those that need a dark background to enhance their form (petals, glowing feel for thread/network). Default to light cards; maximum 1 dark card per screen (4 cards).

Typography

  • Inter family. Title 700 / In-chart values 800 / Axis labels 600. Card structure is a fixed four-piece set: conclusion-based title (h2) + subtitle (legend and time range go here, separated by ·) + chart + source line (all caps, with letter spacing).
  • Title writes a conclusion, not a chart type name: "Revenue by plan" is acceptable; "Bar chart" is not. Better still is one with judgment: "Where we gained, where we bled."
  • Minimum SVG font size: half-width card 6.5px, full-width 5.5px. Information that doesn't fit should be revealed on hover; do not shrink font size to force it in.

Shapes

  • Card border radius: 24px, no border, no shadow; cards are separated by white space. Capsule roundness at the ends of bars (round top for vertical bars, round outer end for horizontal bars).
  • Bar charts must not break the axis. The contract of a bar is length ∝ value; breaking the axis breaks the contract. Correct approaches for extreme values: ① let the extreme value go off the chart (most honest) ② main chart + magnifier inset ③ tear the bar, not the axis (explicitly state it didn't fit).
  • Petal skin (thick black seams + rounded fan petals) only applies to radial charts with equal or near-equal divisions. Wide variances in sector sizes obscure each other and reduce readability.

Animation

  • Entry animation is on by default, quarticOut for fast-in fast-stop, no bouncing (wave entry may use elasticOut). Dots stagger 8–15ms each, bars 80–130ms each.
  • Unified reveal mechanism: play when scroll into view + replay on click (use obsReveal from tokens, with timer cleanup).
  • Must include prefers-reduced-motion degradation (already in the token CSS).
  • Animation must not compromise structure: An effect that requires inventing a new layout to accommodate it does not deserve to exist (lesson from effectScatter).

Data

  • Demo data uses token's rnd(i,k) deterministic pseudo-random; disable Math.random()—refreshes must look identical.
  • Values and visuals are strictly proportional. Area encoding uses Math.sqrt(v) to calculate radius; do not use the value directly as radius.

Three: Division of Two Style Families

Under the same mono palette, there are two worldviews. The choice depends on the context and how many seconds the reader is willing to spend:

Glance Family (18 charts)Lupi Family (close reading, 15 charts)
Basic unitShape (thick bars, large arcs, color blocks)Record (one point = one data item)
Lines2px+, bold and confident0.5–0.7px hairline
AggregationPre-aggregated, gives conclusionsRefuses aggregation, lays out raw materials
How to readOne quick glance (<10s)Lean in and read (30s+)
ContextWeekly reports, dashboards, quick notesAnnual reports, external storytelling pages, posters
EngineChart.js / EChartsHand-written SVG

Default strategy: Lupi Editorial → Lupi Basics → Glance. Without a clear context, do not default to Glance. For annual reports, public account long articles, posters, open source READMEs, portfolios: choose Lupi Editorial first. For less data or when familiar chart types are suitable, choose Lupi Basics. Only enter the Glance candidate pool when neither of the first two has a suitable template, or when the user explicitly requests dashboard, monitoring, weekly report, or a three-second quick read.

Full candidate audit is not "make all charts." First use the data shape to filter candidates that can encode the same ontology, then divide candidates into:

  • Semantically suitable: Each point, line, area, or bead has a real unit behind it or a clear aggregation concept.
  • Visually suitable: Labels fit, density is sufficient, reader can finish reading within expected time.
  • Narratively suitable: The graphic itself can carry the judgment the data batch needs to tell, not just present the numbers.

The final choice is the intersection of all three, not "which template file is easiest to copy." Default audit is completed within Lupi Editorial and Lupi Basics; only extend to Glance when both fail. If the batch requires multiple charts, do a global assignment among candidates: no template repetition, rotate shapes, maximum one dark card, avoid turning the entire page into six similar rings or horizontal strips.

Little data (just a few percentages) does not equal Glance only. The correct path to Lupi-ization is unit decomposition: break aggregated numbers back into countable units (1 point = 1 person / 1 percentage point); density comes from units, not from the number of records. Write unit meanings into the subtitle; only decompose honest units (proportion summing to 100 → 100 points); do not fabricate nonexistent individual records. If rounding causes the total to fall short of 100 (e.g., 49.0+27.4+13.9+5.0+3.2 → 98), write in a footnote "another N were eaten by rounding"; do not make up false units.

Priority path for small data going Lupi (verified through multiple case examples):

  1. First scan all candidates, then choose code skeleton—the Basics group F1–F13 (templates/basics-gallery.html) is the Lupi vocabulary for sparse data: column/line/area/donut/bar/grouped/stacked/scatter/waterfall/heat/progress/dumbbell/treemap; the Editorial group L1–L15 provides per-record, unit-decomposition, relationship, and annotation grammar. Do not directly choose an F chart just because basics-gallery.html has ready-made code.
  2. Start with the template closest to the ontology—multiple-choice percentages prioritize comparing L15, F5, L2; 100% composition prioritize comparing L14, L5, F4, G4; funnel prioritize comparing L13, degraded expression of F1/F5. The basis for selection is the data encoding method, not file order.
  3. Only create new shapes if the library truly lacks a match, and new creations must extend from existing gallery grammar (hairline ticks, deterministic rnd jitter, paint-order glow, all-caps annotations); do not introduce external references—"Lupi style" refers to the visual grammar of the gallery batch, not Giorgia Lupi's personal hand-drawn style.
  4. Small-data charts must be filled with environmental structural layers: half of a gallery's attractiveness comes from non-data furniture (ledger paper horizontal lines, dotted guide rails, rim ticks, pillar grids every 10 units, annotation leader lines). Data layers are honestly sparse; the density budget is spent on furniture. Small-data charts that only draw data + a single baseline will inevitably look poor.

Within the same batch (multi-chart page), templates do not repeat. 15 Lupi-family charts are enough to rotate; when the same data can be hosted by multiple templates, choose one not yet used in this batch.

Four: Chart Decision Tree (Data Shape → Candidates)

Numbers correspond to catalog.md. These are only candidate recall tables; arrows and writing order do not indicate priority. Actual selection must follow: first check all Lupi Editorial and Lupi Basics candidates; only use Glance candidates after confirming no suitable template exists.

  • Few category comparison (≤8) → G3 Chunky Bars ⇄ vertical F1 Rung Bars / horizontal F5 Tick Rows ⇄ L2 Dot Cascade (⚠️ cascade category names are vertical; only usable when the name is ≤4 characters or a short abbreviation; long Chinese category names switch to F5/L5/L12)
  • Multiple choice percentages (each item independent 0–100, total may exceed 100) → G3 Chunky Bars ⇄ L15 Ballot Tally
  • Multi-category distribution (30–60 items) → G12 Stagger Wave
  • Categorical values with positive and negative → G10 Diverging Bar
  • Proportion / 100% composition → G4 Dot Waffle ⇄ L14 Hundred Field ⇄ F4 Tick Donut (default alternative to pie chart); near-equal divisions and needs to look grand → G2 Petal Rose; proportion × intensity dual encoding → G13 Big Slice; stacked by category → F7 Stacked Rungs
  • Two time point comparison (before/after, past/present) → Category level (≤6 categories) → F12 Dumbbell Queue (horizontal, beads = real units) ⇄ F6 Paired Rungs (side-by-side dual ladders); only 2–4 series for trend lines → Glance chunky slope (thick lines, large numbers, conclusion in title). Slope charts with excessive crossing significantly reduce readability; do not add decorative structures just for Lupi-ization.
  • Daily sequence (≤30 days, with range) → G1 Range Capsules ⇄ daily reading F2 Hairline Line ⇄ (90-day level, needs texture) L3 Barcode Lollipop; 30–60 days for shape → F3 Hairline Area
  • Cumulative growth → G18 Draw-in + Counter
  • Dual series causality (input vs output) → G8 Rainfall
  • Real-time data → G17 Dynamic Stream
  • Ranking over time → G16 Bar Race
  • Day × hour × quantity → G14 Single Axis ⇄ F10 Dot Heat
  • Waterfall / increase-decrease decomposition (≤6 levels) → F9 Rung Waterfall
  • Single value progress (0–100%) → F11 Tick Gauge ⇄ G18 Draw-in + Counter
  • Two-dimensional scatter (≤20 points) → F8 Plumb Scatter; hundreds of points distribution → G15 Jitter Strip
  • Grouped distribution, individual records → G15 Jitter Strip
  • Category × category + quantity (matrix) → Light (≤100 cells) L4 Arc Matrix ⇄ Heavy (large range, needs annotations) L9 Bubble Almanac
  • Many-to-one attribution → Strong shape L5 Radial Convergence ⇄ With name list L12 Type Colonnade
  • Funnel / staged decrease → L13 Hourglass Stream
  • Hierarchical structure → G7 Tree LR
  • Hierarchy + share / weight (two levels, positive values) → F13 Nested Treemap; only look at who belongs to whom, not comparison of sizes → G7 Tree LR
  • Event sequence life history → L11 Trend Lineage
  • Multiple entities birth time + current status → L1 Launch Fan
  • Per-event time distribution (within a day) → L10 Radial Patchwork
  • Bipolar scale (both ends are valid) → L7 Brand Spectrum. Note the difference from single-pole scoring (radar chart): single-pole uses ECharts native radar.
  • Network → ≤15 nodes G6/G11 small chart; >15 nodes or needs to look up values → B1 Circular / B2 Force-directed; multi-segment path flow → B3 Threads
  • Multiple groups × grid (needs decorative feel) → L8 Dotty Matrix; needs reading values → flatten using G14
  • Same entity set multi-dimensional carousel (presentation) → G9 Scatter Morph

F13 Nested Treemap Hard Rules

  • Only accepts hierarchical data and non-negative weights; parent values are summed from children; prohibit contradictory parent-child totals. Area is directly delegated to ECharts treemap layout; do not take the square root of values.
  • Default display is two levels (parent group + leaves). Only enable drill-down when there are more than two levels and the reader needs to query layer by layer; normal static deliveries keep nodeClick:false to avoid accidental view changes.
  • Mono grayscale only represents hierarchy; do not assign random shades to each leaf; parent groups are distinguished by title band, inter-group whitespace, and borders. Removing color should still allow clear grouping visibility.
  • porcelain uses single-hue lightness to represent ordered parent group share or hierarchy; palm uses hue for no more than 4 top-level categories; wire keeps grayscale, allowing only one clearly defined protagonist to use HERO.
  • When area already encodes the value, color must not silently repeat the same value without explanation. The subtitle must clearly state area = ..., and when using color, also clearly state color = ....
  • When leaves exceed 30, labels are largely omitted, or the smallest rectangle is too small to form a stable hot zone, first merge the long tail into Other, split into multiple charts, or switch to G7 / L12 / B series relationship charts.
  • Tooltip must display at least the full hierarchy path, original value, and total share proportion; hide labels that don't fit within the card; do not shrink below the minimum font size.

Five: Three Interactive Questions (Determining Static vs Interactive)

Ask in order:

  1. Is there a real record behind this line/point? No (pure decorative texture, e.g., spokes in Cluster Field, flowing lines in Hourglass) → Prohibit adding interactivity; adding hover to elements without content is deceptive.
  2. There is a record → Can it be read without clicking? Elements <50 and both ends are labeled (e.g., Colonnade) → Static is sufficient; hover is a nice-to-have.
  3. Elements >50 or multi-segment paths (e.g., Threads) → Must have hover/pin, otherwise it's just an atmosphere chart. Interactive implementation references templates/big-threads.html: pad a 9px transparent twin line under the visible line as the hot zone; hover a single line highlights the entire path; hover a label pulls the entire bundle; click to pin.

Six: Chart Translation Process for Library-Outside Types

When the user requests a chart not in the 49 templates (or sends a reference image), it's not that it can't be done; it's that you need to make a new sentence on the spot. Four steps, the first step must not be skipped:

  1. First answer the ontology: What does this chart type encode? Which visual channel (position/length/angle/area/lightness/density) corresponds to which data dimension? If you can't answer, ask the user for the data structure. Copying the shape without the soul = wasted effort (pictorial bar once mistakenly made "symbol count" into "tree growing tall," requiring rework).
  2. Find the closest relative: In the catalog, find the chart with the most similar data shape as a starting point, inheriting its layout skeleton and animation rhythm.
  3. Build with tokens: Palette, fonts, rounding, animation parameters all come from mono-tokens.js; do not invent new colors or new font sizes. The output must look "obviously from the same family" as the library charts. When using color, change colors from a single preset in color-presets.js; other tokens still follow mono-tokens.js.
  4. Pass Section 2's hard rules and Section 8's self-check, with the same standards as library charts.

Additional rules for reference image translation: Identify which school the reference image belongs to (Glance or Editorial). Editorial style's density, annotations, and hand-drawn feel (blob) are part of the ontology; don't smooth them out—almanac once required rework for "not being bold enough."

Six Point Five: Color (Automatic Selection by Context, Single Color System)

Mono is the baseline, not a forced answer when color is not triggered. Even when the user does not mention color, evaluate whether color is suitable based on data semantics, number of categories, reading context, and content tone. If the adaptation relationship is unclear, or color does not bring real information value, return to Mono.

The first color draft chooses from three built-in presets; color values are in color-presets.js, samples in templates/color/. Presets are for quickly obtaining a stable, unified first version; they are not locked palettes. When the user says "Make this blue a bit darker," adjust within the current color system; when the user explicitly gives brand colors, color values, or a full palette, build a custom palette according to the rules below. After adjustment, re-check contrast, visual hierarchy, and data semantics.

The same HTML or the same set of deliverables must first lock a global color system: Mono, porcelain, palm, wire, or a custom palette. All charts share that choice. If a particular chart does not support the selected system, do not change its color alone; either switch to a globally compatible system, or return the entire group to Mono.

The structural source is always the original gallery. Check rendering code in the root templates/ gallery; templates/color/ is only for checking color schemes. First select the structure according to Section 0, then decide whether to apply a different skin.

Whether to Use Color

Decide according to the following priority:

  1. User explicitly specifies. When the user requests a certain color, tone, or preset, prioritize compliance, but still check capacity, contrast, and data semantics.
  2. Agent automatic selection. Even if the user doesn't mention color, you may automatically use color as long as the data shape and context have a clear correspondence with one of the presets: ordered single series suits porcelain; a small number of unordered categories suits palm; needing a controlled visual anchor suits wire.
  3. Use Mono when the relationship is unclear. If there are too many categories, high-density records, color has no stable meaning, or the entire group of charts cannot share the same preset, use Mono.

Color is not an upgrade; it is a semantic tool that the Agent can actively choose. In the deliverable, use one sentence to explain the selected color system and the data meaning it carries.

Custom Palette (Only Enabled When User Explicitly Requests It)

The Agent must not invent a fifth default aesthetic on its own. A custom palette is only built when the user gives explicit color values, brand colors, brand guidelines, or "use the color scheme from this reference image"; if the user only says "make it look nicer," still choose from the three built-in presets.

  1. First determine the color logic, then assign color values. Ordered data uses single-hue lightness gradient; unordered categories use categorical colors; when focus is needed, use neutral colors + one accent color. Do not first get five colors, then sprinkle them evenly over all elements.
  2. Establish complete roles, do not scatter hex values directly. custom must at least define BG, TXT, MUT, GRID, DATA; when a focus is needed, define HERO; for ordered data, define RAMP; for categorical data, define CAT. Inline a CUSTOM object in the output; all charts get colors from roles.
  3. Interpret according to input quantity. 1 color generates a single-hue lightness gradient; 2 colors default to main data color + accent color, not automatically treated as two equal categories; 3–6 colors only enter CAT when the data indeed has corresponding categories. More than 6 colors first merge categories, switch to position/labels, or return to Mono.
  4. Allow derived light/dark, prohibit smuggling new hue. Light colors are mixed from the user's color with BG; dark colors from the user's color with TXT; do not borrow color values from porcelain, palm, or wire to fill custom.
  5. Contrast is a hard door. Body text and small labels relative to background, at least 4.5:1; large text at least 3:1; critical borders, data shapes, and interactive states relative to adjacent colors, at least 3:1. When not met, prioritize adjusting lightness; do not arbitrarily change the user-specified main hue.
  6. Color cannot be the only clue. Categories still have labels; ordinal still retains position/length/area; emphasis still has title or annotation explanation. After removing color for color-blind users, the chart's structure should still be readable.
  7. Lock only this one custom palette at a time. custom is not mixed with any built-in preset; multi-chart deliverables share the same CUSTOM. Unless the user explicitly requests the brand color to be solidified as a project-level preset, custom is only inlined in the current output, not written back to color-presets.js.

If the user later requests "a bit darker," "warmer background," or replace a certain color value, modify the corresponding role and re-check the entire set's contrast and semantic mapping; do not only change the named element.

Which Preset to Choose: First Look at Data Shape, Then Tone

Data ShapeAllowedReason
Ordered / single series (progress, heat, time series, single metric, ranking)porcelain, wireThe contract of brightness = data still holds
Unordered categories ≤4palmHue corresponds to category
Unordered categories 5–6palm (barely)Relies on lightness and saturation to aid differentiation
Categories >6Mono grayscaleInsufficient capacity from color presets
Needs restraint but one visual anchorwireGrayscale carries data; orange only marks the protagonist
User might sayPresetTone
Blue, cool, academic, rational, serious, techporcelainSingle-hue blue steps
Green, warm, natural, gentle, vintage, MorandipalmGreen-yellow low saturation, amber as accent
Black and white, restrained, magazine style, editorialwireBlack and gray with a touch of fluorescent orange

Color Hard Rules

  • One delivery uses only one color system. One chart, the same HTML, or the same set of sibling charts can only use Mono, one preset from color-presets.js, or one user-requested custom. Prohibit mixing presets with each other, and prohibit custom borrowing from built-in presets to fill colors.
  • Line width ×1.8, transparency floor .85. Hairlines under grayscale can disappear when changed to light colors; draw heat is the exception.
  • Each chart has at least 3 color steps or positions. When using only 1–2 colors, fall back to grayscale.
  • Colors must connect to real dimensions. Ordinal step connects to values; segmented color connects to months or sections; categorical color connects to categories; footnote clearly states what color encodes.
  • Accent color only for one protagonist. A second protagonist dilutes the emphasis.
  • Data color on dark cards must be lighter than the card background. For large dark-background charts, use the DARK block of the preset. big-circular / big-force / big-threads only exist for porcelain and palm; wire uses the original Mono large charts.
  • In palm, DATA and HERO must be different. Amber and olive have similar lightness; do not treat them as equal category colors.

Seven: When to Say No

Having the courage to refuse is more trustworthy than accepting everything. Following cases are not done, and alternatives should be given:

  • Broken-axis bar chart → Refuse, offer three honest options (off the chart / magnifier / tear bar not axis).
  • Glow / glassmorphism / 3D → Refuse, maintain current visual grammar. Custom color values are mapped per custom rules; cross-color-system mixing is refused.
  • Using multiple hues for a single series → Refuse. Offer porcelain, wire, or fall back to Mono.
  • Categories >6 still wanting color → Refuse, fall back to Mono grayscale.
  • Map types (choropleth, trajectory maps) → The library has no geographic pipeline; honestly say it cannot be done; don't force a skewed version.
  • Adding interactivity to purely decorative elements (Section 5 Q1) → Refuse and explain.
  • Radar chart reconstruction → Do not reconstruct; use ECharts native radar + Mono token skin (proven in practice: in presentation scenarios, "recognizable chart types" have value).
  • Too little data to support the selected chart type (e.g., 3 nodes for a force-directed graph) → Downgrade to a simpler chart and explain.

Eight: Pre-Delivery Self-Checklist

  1. Are values and visuals proportional? (Area uses sqrt? Bars not broken on axis?)
  2. Is the palette controlled? Does the entire HTML or same set of deliverables only use Mono, a single built-in preset, or a single custom? Any non-ladder color in Mono = rework; any color from another preset in built-in color = rework; is custom only getting colors from CUSTOM roles and passing contrast checks?
  3. Will labels overlap? (Barcode lesson: adjacent peak labels must enforce minimum spacing).
  4. Is the minimum font size borderline? (Half-width 6.5 / full-width 5.5).
  5. Is demo data deterministic with rnd? Refreshes look identical?
  6. Is reveal working? (Scroll to start, click to replay, timer not stacking, reduced-motion degradation present).
  7. Have you run node --check on syntax? (Extract <script> content and check).
  8. Is the card four-piece set complete? Is the title a conclusion, not a chart type name?
  9. Does the subtitle clearly explain the legend? (Reader looks at this line, not the code).
  10. Have you completed a full candidate audit? Write down at least 3 candidates and elimination reasons, not just "which template was used."
  11. If multi-chart page, have templates been globally assigned? Are there duplicate silhouettes, excessive dark cards, or all charts becoming the same type of radial chart?
  12. For each chart, have you recorded the chart type number, gallery file, and card title? Does the final chart's core structure truly come from that template, not reinvented?
  13. If using Glance, have you written why Lupi Editorial and Lupi Basics are both unsuitable? If not, rework to Lupi / Basics.
  14. Final question: If you place this chart next to the corresponding card in the selected gallery, is it from the same template family, not just "somewhat similar in style"?

Nine: Single File Template Skeleton

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Mono — {Chart Name}</title>
<!-- When ECharts is needed: -->
<script src="https://cdn.jsdelivr.net/npm/echarts@6/dist/echarts.min.js"></script>
<!-- When Chart.js is needed (G1 / G3): -->
<!-- <script src="https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js"></script> -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="{MONO.FONT.link}" rel="stylesheet">
<style>/* Inline MONO.CARD_CSS */</style>
</head>
<body>
<div class="grid2">
  <div class="card"><!-- or card dark / card wide -->
    <h2>{Conclusion-based title}</h2>
    <div class="sub">{Explanation} · {Legend} · {Time range}</div>
    <!-- Chart container choose one of three engines: -->
    <div class="ch" id="ch"></div><!-- ECharts -->
    <!-- Hand-written SVG: <svg id="ch" viewBox="0 0 400 320"></svg> -->
    <!-- Chart.js (G1/G3): <div class="wrap"><canvas id="ch"></canvas></div>, with .wrap{position:relative;height:320px} -->
    <!-- ⚠️ Chart.js must... -->

<p>… (remaining content truncated for translation)</p>

Related Skills