Back to index

Weighted Decision Scorecard

Table
Generates documents
Weighted Decision Scorecard

Seen as a design

Take it with you

Copy and paste, or save a file and hand it over. For a machine with no network, one “Everything” file is enough.

Everything

weighted-decision-scorecard-everything.md

Everything in this panel, including the contents behind each URL, in one Markdown file

Prompt

1.4 KB
Build an HTML document with "Weighted Decision Scorecard". This layout runs, so there is no composition to rebuild — what it needs is content.

## What this layout does
Weighted Decision Scorecard with explicit source values and reading conditions.

## What you have to supply
- Provide the source values, labels and decision conditions described by the schema.

## The shape of the input
- `title` — string — 結論を伝える見出し
- `subtitle` — string? — 出典・時点・母集団や仮定
- `criteria` — array (label, weight) — 評価軸と重み(合計100)
- `options` — array (label, scores) — 各評価軸に対応する0〜5点

schema.ts holds the machine-checkable validation. Ask rather than guess when an input is missing.

## When not to use it
- Do not compare values with incompatible units, populations, or assumptions.

## How to build it
Put the input in a JSON file and run:

```bash
node scripts/render.mjs weighted-decision-scorecard <input.json> --theme ink -o out.html
```

The output is one self-contained file and fetches nothing at render time.

## The source
- https://design-vault.pages.dev/designs/weighted-decision-scorecard/source/template.tsx
- https://design-vault.pages.dev/designs/weighted-decision-scorecard/source/schema.ts
- https://design-vault.pages.dev/designs/weighted-decision-scorecard/source/sample-data.json
- https://design-vault.pages.dev/designs/weighted-decision-scorecard/sample.html

Files

Template, input schema, sample data and metadata. This document was generated from those four. The generated document

template.tsx

7.1 KB

/designs/weighted-decision-scorecard/source/template.tsx

Show contents
import type { ReactNode } from "react";
import type { Props } from "./schema";


const fmt = (n: number) => Number.isInteger(n) ? n.toLocaleString("ja-JP") : n.toLocaleString("ja-JP", {maximumFractionDigits: 2});
function Ledger({heads,rows,caption}:{heads:string[];rows:ReactNode[][];caption?:string}) { return <table className="ledger">{caption && <caption>{caption}</caption>}<thead><tr>{heads.map((h,i)=><th key={i} scope="col">{h}</th>)}</tr></thead><tbody>{rows.map((r,i)=><tr key={i}>{r.map((v,j)=><td key={j} data-label={heads[j]}>{v}</td>)}</tr>)}</tbody></table>; }
function Notes({children}:{children:ReactNode}) { return <details><summary>データ・判断条件を確認</summary>{children}</details>; }

const CSS = String.raw`
.asset{font-family:var(--font-sans);color:var(--color-primary);background:var(--color-surface);max-width:var(--container-slide);margin:auto;padding:3rem 2rem;line-height:1.6;font-size:var(--text-body-sm)}
.asset *{box-sizing:border-box}.asset header{margin-bottom:2rem}.asset .eyebrow{font-family:var(--font-mono);font-size:var(--text-label);letter-spacing:.08em;color:var(--color-secondary);margin-bottom:.75rem}.asset h1{font-size:var(--text-h1);font-weight:700;line-height:1.35;letter-spacing:-.025em;max-width:32em}.asset h2{font-size:var(--text-h3);font-weight:600;margin-bottom:.75rem}.asset h3{font-size:var(--text-body-md);font-weight:600}.asset .subtitle,.asset .muted{color:var(--color-secondary)}.asset .subtitle{margin-top:.75rem}.asset .number{font-variant-numeric:tabular-nums;font-family:var(--font-mono)}.asset .hero-number{font-size:var(--text-display);line-height:1.2;font-weight:700;letter-spacing:-.04em}.asset .callout{border-left:.25rem solid var(--color-tertiary);padding:1rem 1.5rem;background:var(--color-surface-subtle);margin-bottom:1.5rem}.asset .grid2{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem}.asset .grid3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1.5rem}.asset .panel{padding:1.5rem;background:var(--color-surface-subtle);border-radius:var(--radius-md);min-width:0}.asset .rule{border-top:1px solid var(--color-outline);padding-top:1rem;margin-top:1rem}.asset .pill{display:inline-block;padding:.25rem .75rem;border:1px solid var(--color-outline);border-radius:var(--radius-full);font-size:var(--text-label)}.asset .focus{background:var(--color-tertiary-container);color:var(--color-on-tertiary-container)}.asset .dark{background:var(--color-primary);color:var(--color-on-primary)}.asset .dark .muted{color:var(--color-on-primary-container)}.asset .row{display:grid;grid-template-columns:12rem minmax(0,1fr) 6rem;gap:1rem;align-items:center;padding:.75rem 0;border-bottom:1px solid var(--color-outline)}.asset .row>*{min-width:0}.asset .track{height:1rem;position:relative;background:var(--color-neutral);border-radius:var(--radius-sm)}.asset .bar{height:100%;background:var(--color-tertiary);border-radius:var(--radius-sm)}.asset .track.tall{height:2rem}.asset .flex{display:flex;gap:1rem;align-items:center;justify-content:space-between;flex-wrap:wrap}.asset .stack>*+*{margin-top:1rem}.asset ul{list-style:disc;padding-left:1.25rem}.asset li+li{margin-top:.5rem}.asset .plot{display:block;width:100%;height:auto;overflow:visible}.asset .plot text{font-family:var(--font-sans);font-size:14px;fill:var(--color-secondary)}.asset .plot .ink{fill:var(--color-primary)}.asset .plot .axis{stroke:var(--color-outline);stroke-width:1}.asset .plot .accent{stroke:var(--color-tertiary);fill:none;stroke-width:3}.asset .legend{display:flex;gap:1.5rem;flex-wrap:wrap;font-size:var(--text-label);margin-bottom:1rem}.asset .legend b{display:inline-block;width:.75rem;height:.75rem;margin-right:.5rem}.asset .ledger{border-collapse:collapse;width:100%;font-variant-numeric:tabular-nums}.asset .ledger caption{text-align:left;font-weight:600;margin:1rem 0}.asset .ledger th{font-weight:600;color:var(--color-secondary);text-align:left}.asset .ledger th,.asset .ledger td{padding:.75rem 1rem;border-bottom:1px solid var(--color-outline);vertical-align:top;overflow-wrap:anywhere}.asset .ledger th:first-child,.asset .ledger td:first-child{padding-left:0}.asset .ledger th:last-child,.asset .ledger td:last-child{padding-right:0}.asset .ledger tbody tr:hover{background:var(--color-surface-subtle)}.asset details{border-top:1px solid var(--color-outline);margin-top:1.5rem;padding-top:1rem}.asset summary{cursor:pointer;color:var(--color-secondary);padding:.5rem 0;min-height:2.75rem}.asset summary:focus-visible{outline:2px solid var(--color-tertiary);outline-offset:.25rem}.asset .small{font-size:var(--text-label)}.asset .mobile-only{display:none}.asset .horizontal-list{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1rem}.asset .board-column{border-top:.25rem solid var(--color-primary);padding-top:1rem;min-width:0}.asset .board-item{padding:1rem 0;border-bottom:1px solid var(--color-outline)}.asset .board-item p{margin-top:.5rem}.asset .statement{font-size:var(--text-h2);line-height:1.5;font-weight:600}.asset .meta-line{margin-top:.75rem;font-size:var(--text-label);color:var(--color-secondary)}.asset pre{white-space:pre-wrap;overflow-wrap:anywhere}.asset footer{margin-top:2rem;font-size:var(--text-label);color:var(--color-secondary)}
@media(max-width:640px){.asset{padding:1.5rem 1rem}.asset h1{font-size:var(--text-h2)}.asset header{margin-bottom:1.5rem}.asset .grid2,.asset .grid3,.asset .horizontal-list{grid-template-columns:1fr}.asset .row{grid-template-columns:minmax(0,1fr) 5rem;gap:.5rem}.asset .row>:first-child{grid-column:1/-1}.asset .desktop-only{display:none!important}.asset .mobile-only{display:block}.asset .panel{padding:1rem}.asset .ledger,.asset .ledger tbody,.asset .ledger tr,.asset .ledger td{display:block}.asset .ledger thead{display:none}.asset .ledger tr{padding:.75rem 0;border-bottom:1px solid var(--color-outline)}.asset .ledger td{display:grid;grid-template-columns:7rem minmax(0,1fr);gap:.75rem;border:0;padding:.25rem 0!important}.asset .ledger td:before{content:attr(data-label);color:var(--color-secondary);font-size:var(--text-label)}.asset .hero-number{font-size:var(--text-h1)}}
@media print{.asset{max-width:none;padding:1rem}.asset details>*{display:block}.asset summary{display:none}}
`;

export default function Template(d: Props) {
const ranked=d.options.map(o=>({...o,total:o.scores.reduce((s,v,i)=>s+v*d.criteria[i].weight/100,0)})).sort((a,b)=>b.total-a.total);
return <section className="asset asset-weighted-decision-scorecard"><style>{CSS}</style><header><p className="eyebrow">WEIGHTED DECISION SCORECARD</p><h1>{d.title}</h1>{d.subtitle && <p className="subtitle">{d.subtitle}</p>}</header>
<div className="callout"><strong>{ranked[0].label}</strong> · 加重得点 <strong className="hero-number">{fmt(ranked[0].total)}</strong> / 5</div><Ledger heads={["候補",...d.criteria.map(c=>c.label+"("+c.weight+"%)"),"加重得点"]} rows={ranked.map(o=>[o.label,...o.scores,fmt(o.total)])}/><Notes><p>得点=Σ(評価点×重み÷100)。同点は入力順で表示し、自動で優劣を断定しません。重みや評価点の根拠を変更前に合意します。</p></Notes>
<footer>評価は0〜5点。費用を評価に含める場合は採点基準を合意する。</footer></section>;
}

schema.ts

1.0 KB

/designs/weighted-decision-scorecard/source/schema.ts

Show contents
import { z } from "zod";
const text = z.string().trim().min(1).max(160);
const short = z.string().trim().min(1).max(48);
const value = z.number().finite();
const positive = value.positive();
const unique = (values: string[]) => new Set(values).size === values.length;

export const schema = z.object({
  title: text.describe("結論を伝える見出し"),
  subtitle: text.optional().describe("出典・時点・母集団や仮定"),
  criteria:z.array(z.object({label:short,weight:positive}).strict()).min(2).max(6).describe("評価軸と重み(合計100)"),
  options:z.array(z.object({label:short,scores:z.array(value.min(0).max(5)).min(2).max(6)}).strict()).min(2).max(4).describe("各評価軸に対応する0〜5点"),
}).strict().refine(d=>Math.abs(d.criteria.reduce((s,c)=>s+c.weight,0)-100)<1e-6&&unique(d.criteria.map(c=>c.label))&&unique(d.options.map(o=>o.label))&&d.options.every(o=>o.scores.length===d.criteria.length),"重み合計100・評価軸数・候補の一意性を確認");
export type Props = z.infer<typeof schema>;

meta.yaml

1.4 KB

/designs/weighted-decision-scorecard/source/meta.yaml

Show contents
id: weighted-decision-scorecard
name:
  ja: 重み付き選定スコアカード
  en: Weighted Decision Scorecard
purpose:
  ja: 評価軸の重みと点数を公開し、候補の加重得点を比較する。
  en: Weighted Decision Scorecard with explicit source values and reading conditions.
status: published
still: ./still.png
category: decision
catalogOrder: 420
jobs:
  - compare-choose
useCases:
  - comparison
layoutKinds:
  - table
tags:
  - weighted-decision-scorecard
  - decision
  - offline
  - responsive
whenToUse:
  - ja: 評価軸の重みと点数を公開し、候補の加重得点を比較する。
    en: Use to communicate weighted decision scorecard.
avoidWhen:
  - ja: 同じ条件・単位で比較できないデータには使わない
    en: Do not compare values with incompatible units, populations, or assumptions.
requiredInputs:
  - ja: 評価は0〜5点。費用を評価に含める場合は採点基準を合意する。
    en: Provide the source values, labels and decision conditions described by the schema.
relatedLayouts:
  - comparison-table
  - options-tradeoff
dataSchema:
  title: string — 結論を伝える見出し
  subtitle: string? — 出典・時点・母集団や仮定
  criteria: array (label, weight) — 評価軸と重み(合計100)
  options: array (label, scores) — 各評価軸に対応する0〜5点
sources: []

sample-data.json

652 B

/designs/weighted-decision-scorecard/source/sample-data.json

Show contents
{
  "title": "加重得点はA案が首位、評価条件を共有する",
  "subtitle": "架空サンプル|レイアウトの使用例",
  "criteria": [
    {
      "label": "業務適合",
      "weight": 40
    },
    {
      "label": "運用性",
      "weight": 35
    },
    {
      "label": "導入容易性",
      "weight": 25
    }
  ],
  "options": [
    {
      "label": "A案",
      "scores": [
        4,
        5,
        4
      ]
    },
    {
      "label": "B案",
      "scores": [
        5,
        3,
        4
      ]
    },
    {
      "label": "C案",
      "scores": [
        3,
        4,
        5
      ]
    }
  ]
}