# maging — AI Output Formatter > **AI 답변을, 쓸 수 있는 결과물로.** > 코딩 없이, 디자인 없이 — LLM이 31개 위젯·35개 브랜드 테마로 단일 HTML 대시보드를 바로 생성합니다. --- ## Setup (always include — one-liner) ```html ``` `maging-all.js` bundles in order: Pretendard (Korean font) + maging.css + Tailwind Play CDN + ECharts 5 + maging.js. Dispatches `'maging:ready'` on `window` when all deps are ready. **You MUST mount ALL widgets inside `maging:ready`:** ```js window.addEventListener('maging:ready', () => { Maging.kpiCard('#el', { label: '매출', value: '₩128억', delta: 8.3 }); }); ``` **DO NOT use `DOMContentLoaded`** — it fires before ECharts/maging.js finish loading and throws `"Maging is not defined"`. This is non-negotiable. --- ## Themes (35) Set on ``. Each theme bundles palette, typography, radius, shadow. Changing the attribute instantly re-styles every widget. **Light (18):** `claude` (warm cream+terracotta) · `linear` (indigo minimal) · `stripe` (payment purple) · `notion` (off-white) · `airbnb` (coral) · `linkedin` (corporate blue) · `instagram` (vivid) · `youtube` (red) · `reddit` (orange) · `medium` (editorial green serif) · `apple` (system blue) · `duolingo` (owl green) · `tiffany` (robin-egg blue+gold) · `mailchimp` (cavendish yellow) · `tmobile` (magenta) · `fedex` (purple+orange) · `hermes` (cream serif) · `barbie` (pastel pink) **Dark (17):** `vercel` (pure black) · `github` (dimmed) · `x` (sharp mono) · `slack` (aubergine) · `discord` (blurple) · `openai` (AI teal) · `spotify` (neon green) · `twitch` (gaming purple) · `netflix` (cinematic red) · `figma` (multi) · `amazon` (navy) · `adobe` (creative red) · `bloomberg` (terminal amber) · `nasa` (worm blue+red) · `heineken` (bottle green) · `deere` (tractor green+yellow) · `ups` (pullman brown) Pick by intent: minimal→`linear`/`vercel` · warm→`claude`/`notion` · corporate→`linkedin`/`stripe` · bold→`netflix`/`adobe` · luxury→`hermes`/`tiffany` · playful→`barbie`/`duolingo` · terminal→`bloomberg` · engineering→`nasa`. Default: `claude`. --- ## Layout Primitives These are structural elements mounted on plain divs **outside** grid cells — not card widgets. ```js Maging.pageHeader(selector, { kicker?, title, subtitle?, meta? }) ``` Full-width H1 block: dot·kicker line → large title → subtitle + mono-meta row. Use once at the top of the page. ```js Maging.sectionHead(selector, { index?, kicker?, title, tag? }) ``` Flex row: `"index · kicker" + H2` on the left, tag badge on the right. Use as labeled dividers between grid sections. **Pattern:** ```html
``` ```js Maging.pageHeader('#page-hero', { kicker: 'REPORT', title: '월간 현황', subtitle: '2025년 4월', meta: 'Last updated 09:00 KST' }); Maging.sectionHead('#section-01', { index: '01', kicker: 'TRENDS', title: '처리 추이', tag: 'Line · 6M' }); ``` --- ## Widgets (31) Mount: `window.Maging.(selector, config)`. All auto-refresh on theme change. ### METRIC TILES **`kpiCard`** ```js Maging.kpiCard(sel, { label, // string — metric name value, // string — formatted value e.g. '₩128억' delta?, // number — MoM % change deltaGoodWhen?, // 'positive' (default) | 'negative' sparkline?, // number[] — mini line chart icon?, // string — emoji or symbol compact?, // boolean — hides sparkline, smaller padding (for 110px rows) }) ``` **`metricChart`** ```js Maging.metricChart(sel, { label, value, delta?, // number — % change deltaGoodWhen?, // 'positive' (default) | 'negative' icon?, context?, // caption below delta categories, // string[] — x-axis labels series: [ { name, data: number[] }, // [0] current period (accent line + area) { name, data: number[] }, // [1] previous period (dashed muted) — optional ], target?, // number — horizontal dashed goal line yFormatter?, // (v: number) => string }) ``` Hero number + labeled mini line chart. Shows current vs previous period with x/y axis labels. Use when the user needs to understand scale and compare periods. **`heroTile`** ```js Maging.heroTile(sel, { kicker?, // string — small uppercase label e.g. '이번 달 · Q2 2026' value, // string — the hero number e.g. '₩128억' tagline?, // string — narrative sentence below the number stats?, // [{ label, value }] — 2–4 micro-stats below a divider }) ``` Landing-page style hero. Typography-first — no chart. Use for the single most important number on a dashboard. **`ringProgress`** ```js Maging.ringProgress(sel, { value, max, unit, label, context?, thresholds: [[ratio, level], …] // e.g. [[0.5,'danger'],[0.85,'warning'],[1,'good']] }) ``` **`bulletChart`** ```js Maging.bulletChart(sel, { value, target?, benchmark?, max, min?, ranges?: [{ value, label }], valueFormatter?, unit? }) ``` **`compareCard`** ```js Maging.compareCard(sel, { title, left: { label, value }, right: { label, value }, delta, deltaLabel? }) ``` **`metricStack`** ```js Maging.metricStack(sel, { title, main: { label, value, delta? }, items: [{ label, value }] }) ``` **`countdownTile`** ```js Maging.countdownTile(sel, { title, target, label?, context? }) // target = ISO datetime string e.g. '2025-12-31T00:00:00' ``` **`sparklineList`** ```js Maging.sparklineList(sel, { title, items: [{ label, value, delta, sparkline: number[], deltaGoodWhen? }] }) ``` **`goalGrid`** ```js Maging.goalGrid(sel, { title, items: [{ label, value, max, unit?, sublabel? }], thresholds? }) ``` --- ### CHARTS **`lineChart`** ```js Maging.lineChart(sel, { title, subtitle?, categories: string[], series: [{ name, data: number[] }], stack?, area?, yFormatter?, yMin?, yMax? }) ``` **`barChart`** ```js Maging.barChart(sel, { title, subtitle?, items: [{ label, value }], horizontal?, // boolean — use for long Korean labels yFormatter?, showLabels? }) ``` **`donutChart`** ```js Maging.donutChart(sel, { title, subtitle?, slices: [{ label, value, color? }], centerLabel?, centerValue? }) ``` **`funnelChart`** ```js Maging.funnelChart(sel, { title, stages: [{ label, value }], valueSuffix? }) ``` **`gaugeChart`** ```js Maging.gaugeChart(sel, { title, label, value, max, unit, thresholds: [[ratio, level], …] // e.g. [[0.7,'danger'],[0.9,'warning'],[1,'good']] }) ``` **`radarChart`** ```js Maging.radarChart(sel, { title, indicators: [{ name, max }], series: [{ name, data: number[] }] }) ``` **`heatmapChart`** ```js Maging.heatmapChart(sel, { title, xAxis: string[], yAxis: string[], matrix: number[][], // matrix[row][col] tooltipFormatter? }) ``` **`treemapChart`** ```js Maging.treemapChart(sel, { title, items: [{ name, value }], valueFormatter? }) ``` **`scatterChart`** ```js Maging.scatterChart(sel, { title, points: [{ label, x, y, size }], xLabel?, yLabel? }) ``` **`sankeyChart`** ```js Maging.sankeyChart(sel, { title, nodes: [{ name }], links: [{ source, target, value }], valueFormatter? }) ``` **`waterfallChart`** ```js Maging.waterfallChart(sel, { title, items: [{ label, value, type? }], valueFormatter? }) // type auto-detected: first item=start, last=total, positive=gain, negative=loss ``` **`mapChart`** ```js Maging.mapChart(sel, { title, items: [{ region, value }], valueFormatter? }) // region = Korean province name: 서울 경기 부산 인천 대구 대전 광주 울산 세종 // 강원 충북 충남 전북 전남 경북 경남 제주 ``` **`cohortMatrix`** ```js Maging.cohortMatrix(sel, { title, cohorts: string[], // row labels e.g. ['Jan','Feb'] periods: string[], // col labels e.g. ['M0','M1','M2'] data: number[][], // data[i][j] = retention %, null = blank cell sizes?: number[], cohortLabel?, sizeLabel?, valueFormatter? }) ``` --- ### LISTS & STATUS **`leaderboard`** ```js Maging.leaderboard(sel, { title, items: [{ name, initial, percent, meta }] }) ``` **`activityTable`** ```js Maging.activityTable(sel, { title, subtitle?, columns: [{ key, label, align?, render? }], rows: [...], live? }) // render signature: (value, row) => string // SAFER: pre-format rows as plain strings and omit render entirely ``` **`timeline`** ```js Maging.timeline(sel, { title, items: [{ time, text, type? }] // type: 'success'|'warning'|'danger'|'info' }) ``` **`inboxPreview`** ```js Maging.inboxPreview(sel, { title, subtitle?, items: [{ icon, text, time, type }], footer? }) ``` **`statusGrid`** ```js Maging.statusGrid(sel, { title, subtitle?, columns?, // number of grid columns, default 3 items: [{ label, status, value? }] // status: 'ok'|'warning'|'danger' }) ``` --- ### CALENDAR & PROJECT **`calendarHeatmap`** ```js Maging.calendarHeatmap(sel, { title, year, values: [[date, value], …], // date = 'YYYY-MM-DD' max?, valueSuffix?, cellSize? }) ``` **`eventCalendar`** ```js Maging.eventCalendar(sel, { title, year, month, events: [{ date, label, type? }], startOfWeek?, showList?, listFilter? }) ``` **`progressStepper`** ```js Maging.progressStepper(sel, { title, kicker?, status?, meta, steps: [{ label, date, status, badge? }] // step status: 'done'|'active'|'pending' }) ``` --- ### CONTROL & MESSAGING **`alertBanner`** ```js Maging.alertBanner(sel, { type, // 'info'|'warning'|'danger'|'success' title, message?, icon?, action?: { label, href? }, dismissable? }) ``` Horizontal stripe — NOT a card. Place before the grid. --- ## Canonical Layouts Outer wrapper: `
`. Stack sections with `mt-4`. ### 1 · KPI Row ```html
``` 4× `kpiCard`. For 6 compact: `md:grid-cols-6 gap-3` + `grid-auto-rows:110px` + `compact:true`. ### 2 · Hero + Side (2:1) ```html
``` Left: `lineChart`/`barChart`/`funnelChart`. Right: `donutChart`/`leaderboard`/`statusGrid`/`metricStack`. ### 3 · Equal Split (1:1) ```html
``` ### 4 · Metric Trio (1:1:1) ```html
``` 3× `gaugeChart` or `compareCard`. ### 5 · Full-Width Detail ```html
``` `treemapChart` · `sankeyChart` · `calendarHeatmap` · `cohortMatrix` · `mapChart` (use 600px). ### Height tokens `mini 110px` · `tile 192px` · `gauge 240px` · `card 400px` · `detail 520px` · `tall 600px` --- ## Generation Rules 0. **Default = static snapshot.** You are the analyst — pick the story, arrange widgets, no interactive state. No JS state objects, re-render functions, or event handlers (beyond widget internals) unless user explicitly asks for "interactive" / "filterable" / "실시간". 1. Include the one-liner setup. 2. Pick ONE theme via ``. 3. ``. 4. Compose layout from the 5 canonical patterns. Pick heights from the token list. 5. Mount ALL widgets inside `window.addEventListener('maging:ready', () => { … })`. Never use `DOMContentLoaded`. 6. Widget choice by data shape: - Time series → `lineChart` · Categorical → `barChart` · Share → `donutChart` - Funnel → `funnelChart` · Target vs actual → `bulletChart`/`ringProgress` - Distribution → `treemapChart`/`heatmapChart` · Flow → `sankeyChart` - Correlation → `scatterChart` · Korean geo → `mapChart` - Retention → `cohortMatrix` · P&L → `waterfallChart` · Rankings → `leaderboard` - Events → `timeline`/`activityTable` · Health → `statusGrid`+`gaugeChart` - OKR → `goalGrid` · Multi-trend → `sparklineList` · Hero metric → `heroTile` 7. KRW: `v => '₩' + (v/1e8).toFixed(1) + '억'` or `Maging.fmt.krw(v)`. 8. Korean labels OK. Use `word-break: keep-all` for Korean text. 9. Section order: at-a-glance → real-time → trends → deep-dive → operations. 10. Output one fenced code block: ` ```html … ``` `. No text outside it. --- ## NEVER DO - **No code comments** (`//`, `/* */`, ``). Every comment burns output tokens. Widget calls + named IDs are self-documenting. - **No custom `