bigpowers 2.4.0 → 2.5.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/.pi/package.json +2 -2
- package/.pi/prompts/align-grid.md +102 -0
- package/.pi/prompts/compose-workflow.md +1 -1
- package/.pi/prompts/diagnose-root.md +1 -1
- package/.pi/prompts/evolve-skill.md +1 -1
- package/.pi/prompts/grill-with-docs.md +1 -1
- package/.pi/prompts/research-first.md +1 -1
- package/.pi/prompts/reset-baseline.md +1 -1
- package/.pi/prompts/run-evals.md +1 -1
- package/.pi/prompts/scope-work.md +1 -1
- package/.pi/prompts/search-skills.md +1 -1
- package/.pi/prompts/setup-environment.md +1 -1
- package/.pi/prompts/simulate-agents.md +1 -1
- package/.pi/prompts/slice-tasks.md +1 -1
- package/.pi/prompts/stocktake-skills.md +1 -1
- package/.pi/prompts/verify-work.md +1 -1
- package/.pi/skills/align-grid/SKILL.md +104 -0
- package/.pi/skills/assess-impact/SKILL.md +2 -1
- package/.pi/skills/audit-code/SKILL.md +1 -0
- package/.pi/skills/build-epic/SKILL.md +1 -0
- package/.pi/skills/change-request/SKILL.md +1 -0
- package/.pi/skills/commit-message/SKILL.md +1 -0
- package/.pi/skills/compose-workflow/SKILL.md +2 -1
- package/.pi/skills/craft-skill/SKILL.md +1 -0
- package/.pi/skills/deepen-architecture/SKILL.md +1 -0
- package/.pi/skills/define-language/SKILL.md +2 -1
- package/.pi/skills/define-success/SKILL.md +2 -1
- package/.pi/skills/delegate-task/SKILL.md +1 -0
- package/.pi/skills/design-interface/SKILL.md +2 -1
- package/.pi/skills/develop-tdd/SKILL.md +1 -0
- package/.pi/skills/diagnose-root/SKILL.md +2 -1
- package/.pi/skills/dispatch-agents/SKILL.md +1 -0
- package/.pi/skills/edit-document/SKILL.md +1 -0
- package/.pi/skills/elaborate-spec/SKILL.md +2 -1
- package/.pi/skills/enforce-first/SKILL.md +2 -1
- package/.pi/skills/evolve-skill/SKILL.md +2 -1
- package/.pi/skills/execute-plan/SKILL.md +1 -0
- package/.pi/skills/fix-bug/SKILL.md +1 -0
- package/.pi/skills/grill-me/SKILL.md +2 -1
- package/.pi/skills/grill-with-docs/SKILL.md +2 -1
- package/.pi/skills/guard-git/SKILL.md +1 -0
- package/.pi/skills/hook-commits/SKILL.md +1 -0
- package/.pi/skills/inspect-quality/SKILL.md +2 -1
- package/.pi/skills/investigate-bug/SKILL.md +2 -1
- package/.pi/skills/kickoff-branch/SKILL.md +2 -1
- package/.pi/skills/map-codebase/SKILL.md +2 -1
- package/.pi/skills/migrate-spec/SKILL.md +1 -0
- package/.pi/skills/model-domain/SKILL.md +1 -0
- package/.pi/skills/orchestrate-project/SKILL.md +1 -0
- package/.pi/skills/organize-workspace/SKILL.md +2 -1
- package/.pi/skills/plan-refactor/SKILL.md +1 -0
- package/.pi/skills/plan-release/SKILL.md +2 -1
- package/.pi/skills/plan-work/SKILL.md +2 -1
- package/.pi/skills/release-branch/SKILL.md +2 -1
- package/.pi/skills/request-review/SKILL.md +1 -0
- package/.pi/skills/research-first/SKILL.md +2 -1
- package/.pi/skills/reset-baseline/SKILL.md +2 -1
- package/.pi/skills/respond-review/SKILL.md +1 -0
- package/.pi/skills/run-evals/SKILL.md +2 -1
- package/.pi/skills/run-planning/SKILL.md +2 -1
- package/.pi/skills/scope-work/SKILL.md +2 -1
- package/.pi/skills/search-skills/SKILL.md +2 -1
- package/.pi/skills/seed-conventions/SKILL.md +1 -0
- package/.pi/skills/session-state/SKILL.md +1 -0
- package/.pi/skills/setup-environment/SKILL.md +2 -1
- package/.pi/skills/simulate-agents/SKILL.md +2 -1
- package/.pi/skills/slice-tasks/SKILL.md +2 -1
- package/.pi/skills/spike-prototype/SKILL.md +2 -1
- package/.pi/skills/stocktake-skills/SKILL.md +2 -1
- package/.pi/skills/survey-context/SKILL.md +1 -0
- package/.pi/skills/terse-mode/SKILL.md +2 -1
- package/.pi/skills/trace-requirement/SKILL.md +2 -1
- package/.pi/skills/using-bigpowers/SKILL.md +2 -1
- package/.pi/skills/validate-fix/SKILL.md +2 -1
- package/.pi/skills/verify-work/SKILL.md +2 -1
- package/.pi/skills/visual-dashboard/SKILL.md +1 -0
- package/.pi/skills/wire-observability/SKILL.md +1 -0
- package/.pi/skills/write-document/SKILL.md +1 -0
- package/CHANGELOG.md +14 -0
- package/SKILL-INDEX.md +34 -33
- package/align-grid/SKILL.md +108 -0
- package/align-grid/scripts/grid_tokens.py +201 -0
- package/align-grid/scripts/verify_grid.js +140 -0
- package/dashboard/src/web/client.html +191 -249
- package/package.json +1 -1
- package/scripts/generate-reference-tables.sh +1 -1
- package/scripts/sync-skills.sh +22 -10
- package/scripts/validate-skill-yaml.py +73 -0
- package/visual-dashboard/scripts/cockpit.html +123 -16
- package/visual-dashboard/scripts/frame-template.html +181 -45
- package/countable-story-format.md +0 -293
package/scripts/sync-skills.sh
CHANGED
|
@@ -31,13 +31,17 @@ for skill_dir in "$REPO_ROOT"/*/; do
|
|
|
31
31
|
skill_md="$skill_dir/SKILL.md"
|
|
32
32
|
[[ -f "$skill_md" ]] || continue
|
|
33
33
|
|
|
34
|
-
# Extract name and description from YAML frontmatter
|
|
34
|
+
# Extract name, model, and description from YAML frontmatter
|
|
35
35
|
name=$(awk '/^---/{f++} f==1 && /^name:/{print; exit}' "$skill_md" | sed 's/^name:[[:space:]]*//')
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
model=$(awk '/^---/{f++} f==1 && /^model:/{print; exit}' "$skill_md" | sed 's/^model:[[:space:]]*//')
|
|
37
|
+
# Capture description: from "description:" line to next YAML key or closing ---
|
|
38
|
+
description=$(awk '/^---/{f++; next} f==1 && /^description:/{p=1; sub(/^description:[[:space:]]*/,""); print; next} f==1 && p && /^[a-z]+:/{exit} f==1 && p{print}' "$skill_md" \
|
|
38
39
|
| tr -d '\n' \
|
|
39
40
|
| sed -E 's/[[:space:]]+/ /g')
|
|
40
41
|
|
|
42
|
+
# Escape double quotes and backslashes for safe double-quoted YAML output
|
|
43
|
+
description_escaped=$(echo "$description" | sed 's/\\/\\\\/g; s/"/\\"/g')
|
|
44
|
+
|
|
41
45
|
[[ -z "$name" ]] && continue
|
|
42
46
|
|
|
43
47
|
# Build concatenated content: SKILL.md body + all other *.md files alphabetically
|
|
@@ -55,7 +59,7 @@ for skill_dir in "$REPO_ROOT"/*/; do
|
|
|
55
59
|
cursor_file="$CURSOR_RULES/$name.mdc"
|
|
56
60
|
{
|
|
57
61
|
echo "---"
|
|
58
|
-
echo "description: \"$
|
|
62
|
+
echo "description: \"$description_escaped\""
|
|
59
63
|
echo "alwaysApply: false"
|
|
60
64
|
echo "---"
|
|
61
65
|
echo ""
|
|
@@ -67,7 +71,7 @@ for skill_dir in "$REPO_ROOT"/*/; do
|
|
|
67
71
|
{
|
|
68
72
|
echo "---"
|
|
69
73
|
echo "name: $name"
|
|
70
|
-
echo "description: \"$
|
|
74
|
+
echo "description: \"$description_escaped\""
|
|
71
75
|
echo "---"
|
|
72
76
|
echo ""
|
|
73
77
|
echo "$body"
|
|
@@ -79,11 +83,8 @@ for skill_dir in "$REPO_ROOT"/*/; do
|
|
|
79
83
|
prompt_file="commands/prompts/$name.md"
|
|
80
84
|
echo "$body" > "$GEMINI_EXT_DIR/$prompt_file"
|
|
81
85
|
|
|
82
|
-
# Escape double quotes and backslashes for TOML
|
|
83
|
-
description_toml=$(echo "$description" | sed 's/\\/\\\\/g; s/"/\\"/g')
|
|
84
|
-
|
|
85
86
|
{
|
|
86
|
-
echo "description = \"$
|
|
87
|
+
echo "description = \"$description_escaped\""
|
|
87
88
|
echo "prompt = \"@{$prompt_file}\""
|
|
88
89
|
} > "$GEMINI_COMMANDS/$name.toml"
|
|
89
90
|
|
|
@@ -93,7 +94,8 @@ for skill_dir in "$REPO_ROOT"/*/; do
|
|
|
93
94
|
{
|
|
94
95
|
echo "---"
|
|
95
96
|
echo "name: $name"
|
|
96
|
-
echo "description: \"$
|
|
97
|
+
echo "description: \"$description_escaped\""
|
|
98
|
+
[[ -n "$model" ]] && echo "model: $model"
|
|
97
99
|
echo "---"
|
|
98
100
|
echo ""
|
|
99
101
|
echo "$body"
|
|
@@ -206,6 +208,16 @@ if [[ -f "$manifest" ]]; then
|
|
|
206
208
|
fi
|
|
207
209
|
fi
|
|
208
210
|
|
|
211
|
+
# Regression guard (BUG-2026-06-18T100000): validate generated YAML frontmatter
|
|
212
|
+
validate_script="$REPO_ROOT/scripts/validate-skill-yaml.py"
|
|
213
|
+
if [[ -f "$validate_script" ]] && command -v python3 &>/dev/null; then
|
|
214
|
+
if ! python3 "$validate_script" > /dev/null 2>&1; then
|
|
215
|
+
echo "sync-skills: FAIL — YAML frontmatter validation failed" >&2
|
|
216
|
+
python3 "$validate_script" >&2
|
|
217
|
+
exit 1
|
|
218
|
+
fi
|
|
219
|
+
fi
|
|
220
|
+
|
|
209
221
|
# Regenerate derived reference tables from live SKILL.md frontmatter
|
|
210
222
|
bash "$REPO_ROOT/scripts/generate-reference-tables.sh"
|
|
211
223
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Validate YAML frontmatter in all .pi/skills/*/SKILL.md files."""
|
|
3
|
+
import glob
|
|
4
|
+
import sys
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
import yaml
|
|
9
|
+
except ImportError:
|
|
10
|
+
print("ERROR: PyYAML required — pip install pyyaml")
|
|
11
|
+
sys.exit(2)
|
|
12
|
+
|
|
13
|
+
SKILLS_DIR = ".pi/skills"
|
|
14
|
+
files = sorted(glob.glob(f"{SKILLS_DIR}/*/SKILL.md"))
|
|
15
|
+
|
|
16
|
+
parse_failures = []
|
|
17
|
+
semantic_failures = []
|
|
18
|
+
passed = []
|
|
19
|
+
|
|
20
|
+
for path in files:
|
|
21
|
+
skill_name = os.path.basename(os.path.dirname(path))
|
|
22
|
+
with open(path) as f:
|
|
23
|
+
content = f.read()
|
|
24
|
+
|
|
25
|
+
parts = content.split("---", 2)
|
|
26
|
+
if len(parts) < 3:
|
|
27
|
+
parse_failures.append((skill_name, "missing frontmatter delimiters"))
|
|
28
|
+
continue
|
|
29
|
+
|
|
30
|
+
frontmatter = parts[1]
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
data = yaml.safe_load(frontmatter)
|
|
34
|
+
except yaml.YAMLError as e:
|
|
35
|
+
parse_failures.append((skill_name, str(e).split("\n")[0]))
|
|
36
|
+
continue
|
|
37
|
+
|
|
38
|
+
if data is None:
|
|
39
|
+
parse_failures.append((skill_name, "empty frontmatter"))
|
|
40
|
+
continue
|
|
41
|
+
|
|
42
|
+
# Semantic check: model hint embedded in description
|
|
43
|
+
desc = data.get("description", "")
|
|
44
|
+
if desc and "model: sonnet" in desc:
|
|
45
|
+
semantic_failures.append(skill_name)
|
|
46
|
+
|
|
47
|
+
passed.append(skill_name)
|
|
48
|
+
|
|
49
|
+
# Report
|
|
50
|
+
print(f"Total SKILL.md files: {len(files)}")
|
|
51
|
+
print(f"Parse OK: {len(passed)}")
|
|
52
|
+
print(f"Parse FAIL: {len(parse_failures)}")
|
|
53
|
+
print(f"Semantic issues (model in desc): {len(semantic_failures)}")
|
|
54
|
+
print()
|
|
55
|
+
|
|
56
|
+
if parse_failures:
|
|
57
|
+
print("=== PARSE FAILURES ===")
|
|
58
|
+
for name, err in parse_failures:
|
|
59
|
+
print(f" {name}: {err}")
|
|
60
|
+
print()
|
|
61
|
+
|
|
62
|
+
if semantic_failures:
|
|
63
|
+
print("=== SEMANTIC ISSUES (model embedded in description) ===")
|
|
64
|
+
for name in sorted(semantic_failures):
|
|
65
|
+
print(f" {name}")
|
|
66
|
+
print()
|
|
67
|
+
|
|
68
|
+
if parse_failures or semantic_failures:
|
|
69
|
+
print(f"FAIL: {len(parse_failures)} parse + {len(semantic_failures)} semantic issues")
|
|
70
|
+
sys.exit(1)
|
|
71
|
+
else:
|
|
72
|
+
print("PASS: all SKILL.md YAML frontmatter valid")
|
|
73
|
+
sys.exit(0)
|
|
@@ -4,27 +4,100 @@
|
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<title>bigpowers cockpit</title>
|
|
6
6
|
<style>
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
/* ===== GRID TOKENS ===== */
|
|
8
|
+
:root{
|
|
9
|
+
--cols:12;
|
|
10
|
+
--bl:8px;
|
|
11
|
+
--lh:24px;
|
|
12
|
+
--gutter:24px;
|
|
13
|
+
--margin:72px;
|
|
14
|
+
--pad:96px;
|
|
15
|
+
--maxw:1296px;
|
|
16
|
+
--paper:#ffffff;
|
|
17
|
+
--ink:#111315;
|
|
18
|
+
--ink-soft:#5b6066;
|
|
19
|
+
--accent:#e4002b;
|
|
20
|
+
--g-col:rgba(228,0,43,.075);
|
|
21
|
+
--g-edge:rgba(228,0,43,.40);
|
|
22
|
+
--g-base:rgba(0,150,140,.34);
|
|
23
|
+
--g-base-min:rgba(0,150,140,.12);
|
|
24
|
+
}
|
|
25
|
+
*{box-sizing:border-box;}
|
|
26
|
+
body{margin:0;background:var(--paper);color:var(--ink);
|
|
27
|
+
font-family:"Inter",system-ui,sans-serif;font-size:16px;line-height:var(--lh);
|
|
28
|
+
-webkit-font-smoothing:antialiased;}
|
|
29
|
+
|
|
30
|
+
/* ---- scaffold ---- */
|
|
31
|
+
.spread{position:relative;width:100%;}
|
|
32
|
+
.wrap{position:relative;max-width:var(--maxw);margin:0 auto;padding:var(--lh) var(--margin);}
|
|
33
|
+
.grid{display:grid;grid-template-columns:repeat(var(--cols),1fr);
|
|
34
|
+
column-gap:var(--gutter);row-gap:var(--lh);}
|
|
35
|
+
.band{grid-column:1 / -1;display:grid;grid-template-columns:subgrid;
|
|
36
|
+
column-gap:var(--gutter);row-gap:var(--lh);align-items:start;}
|
|
37
|
+
@supports not (grid-template-columns:subgrid){
|
|
38
|
+
.band{grid-template-columns:repeat(var(--cols),1fr);}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* ---- toggle & guides ---- */
|
|
42
|
+
.guides{position:absolute;inset:0;pointer-events:none;z-index:60;opacity:0;
|
|
43
|
+
transition:opacity .26s ease;}
|
|
44
|
+
body.grid-on .guides{opacity:1;}
|
|
45
|
+
.guides .cols{position:absolute;top:0;bottom:0;left:var(--margin);right:var(--margin);
|
|
46
|
+
display:grid;grid-template-columns:repeat(var(--cols),1fr);column-gap:var(--gutter);}
|
|
47
|
+
.guides .col{background:var(--g-col);
|
|
48
|
+
box-shadow:inset 1px 0 0 var(--g-edge),inset -1px 0 0 var(--g-edge);position:relative;}
|
|
49
|
+
.guides .col span{position:absolute;top:32px;left:0;right:0;text-align:center;
|
|
50
|
+
font-family:"Space Mono",monospace;font-size:10px;line-height:1;color:var(--accent);}
|
|
51
|
+
.guides .rows{position:absolute;left:var(--margin);right:var(--margin);top:0;bottom:0;
|
|
52
|
+
background-image:
|
|
53
|
+
repeating-linear-gradient(to bottom,var(--g-base) 0 1px,transparent 1px var(--lh)),
|
|
54
|
+
repeating-linear-gradient(to bottom,var(--g-base-min) 0 1px,transparent 1px var(--bl));}
|
|
55
|
+
.guides .mline{position:absolute;top:0;bottom:0;width:1px;background:var(--g-edge);}
|
|
56
|
+
.guides .mline.l{left:var(--margin);} .guides .mline.r{right:var(--margin);}
|
|
57
|
+
|
|
58
|
+
.toggle{position:fixed;top:18px;right:18px;z-index:200;display:flex;align-items:center;gap:10px;
|
|
59
|
+
background:var(--ink);color:#fff;border:none;cursor:pointer;font-family:"Space Mono",monospace;
|
|
60
|
+
font-size:12px;letter-spacing:.14em;text-transform:uppercase;padding:11px 14px;}
|
|
61
|
+
.toggle .dot{width:9px;height:9px;border-radius:50%;background:#555;}
|
|
62
|
+
body.grid-on .toggle{background:var(--accent);} body.grid-on .toggle .dot{background:#fff;}
|
|
63
|
+
|
|
64
|
+
/* ===== COCKPIT STYLES ===== */
|
|
65
|
+
header { padding: var(--lh) 0; background: var(--paper); color: var(--ink); display: flex; gap: var(--gutter); flex-wrap: wrap; border-bottom: 2px solid var(--ink); margin-bottom: var(--lh); }
|
|
66
|
+
header strong { color: var(--accent); }
|
|
67
|
+
header span { color: var(--ink-soft); }
|
|
68
|
+
|
|
69
|
+
section { padding: var(--lh) 0; border-top: 1px solid #ddd; }
|
|
70
|
+
section h2 { margin: 0 0 var(--lh) 0; font-size: 16px; line-height: var(--lh); text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-soft); }
|
|
71
|
+
.epic { padding: 0 0 calc(var(--lh) - 1px) 0; margin-bottom: var(--lh); border-bottom: 1px solid #eee; }
|
|
72
|
+
.epic:last-child { margin-bottom: 0; border-bottom: none; }
|
|
73
|
+
.epic strong { color: var(--ink); }
|
|
16
74
|
.done { color: #0a7; }
|
|
17
75
|
.pending { color: #c80; }
|
|
18
|
-
#err { color: #c00; padding:
|
|
76
|
+
#err { color: #c00; padding: var(--lh) 0; grid-column: 1 / -1; }
|
|
19
77
|
</style>
|
|
20
78
|
</head>
|
|
21
79
|
<body>
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
80
|
+
<div class="spread">
|
|
81
|
+
<div class="wrap">
|
|
82
|
+
<div class="grid">
|
|
83
|
+
<div class="band">
|
|
84
|
+
<header id="hdr" class="opt-align" style="grid-column: 1 / -1;">Loading…</header>
|
|
85
|
+
</div>
|
|
86
|
+
<div class="band">
|
|
87
|
+
<div id="err" hidden style="grid-column: 1 / -1;"></div>
|
|
88
|
+
<section id="planning" style="grid-column: 1 / 7;"><h2 class="opt-align">Planning</h2><div id="planning-body"></div></section>
|
|
89
|
+
<section id="build" style="grid-column: 7 / 13;"><h2 class="opt-align">Epics & status</h2><div id="build-body"></div></section>
|
|
90
|
+
</div>
|
|
91
|
+
<!-- GRID GUIDES -->
|
|
92
|
+
<div class="guides" aria-hidden="true">
|
|
93
|
+
<div class="cols"></div><div class="rows"></div>
|
|
94
|
+
<div class="mline l"></div><div class="mline r"></div>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<button id="gridToggle" class="toggle"><span class="dot"></span> <span class="lbl">Show grid</span> <kbd>G</kbd></button>
|
|
100
|
+
|
|
28
101
|
<script>
|
|
29
102
|
const params = new URLSearchParams(location.search);
|
|
30
103
|
const projectDir = params.get('projectDir') || '';
|
|
@@ -61,6 +134,40 @@
|
|
|
61
134
|
document.getElementById('err').hidden = false;
|
|
62
135
|
document.getElementById('err').textContent = e.message;
|
|
63
136
|
});
|
|
137
|
+
|
|
138
|
+
/* ===== GRID SCRIPT ===== */
|
|
139
|
+
var btn=document.getElementById('gridToggle');
|
|
140
|
+
function setGrid(on){document.body.classList.toggle('grid-on',on);
|
|
141
|
+
if(btn){btn.setAttribute('aria-pressed',on?'true':'false');
|
|
142
|
+
var l=btn.querySelector('.lbl'); if(l) l.textContent=on?'Hide grid':'Show grid';}}
|
|
143
|
+
if(btn) btn.addEventListener('click',function(){setGrid(!document.body.classList.contains('grid-on'));});
|
|
144
|
+
document.addEventListener('keydown',function(e){
|
|
145
|
+
if((e.key==='g'||e.key==='G')&&!e.metaKey&&!e.ctrlKey&&!e.altKey){
|
|
146
|
+
setGrid(!document.body.classList.contains('grid-on'));}});
|
|
147
|
+
|
|
148
|
+
document.querySelectorAll('.guides .cols').forEach(function(h){
|
|
149
|
+
var n=getComputedStyle(document.documentElement).getPropertyValue('--cols').trim()||'12';
|
|
150
|
+
for(var i=1;i<=parseInt(n,10);i++){var c=document.createElement('div');c.className='col';
|
|
151
|
+
var s=document.createElement('span');s.textContent=i;c.appendChild(s);h.appendChild(c);}});
|
|
152
|
+
|
|
153
|
+
(function(){
|
|
154
|
+
var cvs=document.createElement('canvas'),ctx=cvs.getContext('2d');
|
|
155
|
+
var sel='.opt-align';
|
|
156
|
+
function align(){
|
|
157
|
+
document.querySelectorAll(sel).forEach(function(el){
|
|
158
|
+
el.style.marginLeft='0px';
|
|
159
|
+
var cs=getComputedStyle(el),ch=(el.textContent||'').trim().charAt(0); if(!ch) return;
|
|
160
|
+
if(cs.textTransform==='uppercase') ch=ch.toUpperCase();
|
|
161
|
+
ctx.font=cs.fontStyle+' '+cs.fontWeight+' '+cs.fontSize+' '+cs.fontFamily;
|
|
162
|
+
ctx.textAlign='left';
|
|
163
|
+
var abl=ctx.measureText(ch).actualBoundingBoxLeft;
|
|
164
|
+
if(isFinite(abl)) el.style.marginLeft=abl.toFixed(2)+'px';
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
if(document.fonts&&document.fonts.ready){document.fonts.ready.then(align);}
|
|
168
|
+
align();
|
|
169
|
+
var t;window.addEventListener('resize',function(){clearTimeout(t);t=setTimeout(align,120);});
|
|
170
|
+
})();
|
|
64
171
|
</script>
|
|
65
172
|
</body>
|
|
66
173
|
</html>
|
|
@@ -5,14 +5,17 @@
|
|
|
5
5
|
<title>Bigpowers Dashboard</title>
|
|
6
6
|
<style>
|
|
7
7
|
/*
|
|
8
|
-
* DASHBOARD FRAME TEMPLATE
|
|
8
|
+
* DASHBOARD FRAME TEMPLATE - MULLER-BROCKMANN GRID
|
|
9
9
|
*/
|
|
10
|
+
:root{
|
|
11
|
+
--cols:12;
|
|
12
|
+
--bl:8px;
|
|
13
|
+
--lh:24px;
|
|
14
|
+
--gutter:24px;
|
|
15
|
+
--margin:72px;
|
|
16
|
+
--pad:48px;
|
|
17
|
+
--maxw:1296px;
|
|
10
18
|
|
|
11
|
-
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
12
|
-
html, body { height: 100%; overflow: hidden; }
|
|
13
|
-
|
|
14
|
-
/* ===== THEME VARIABLES ===== */
|
|
15
|
-
:root {
|
|
16
19
|
--bg-primary: #f5f5f7;
|
|
17
20
|
--bg-secondary: #ffffff;
|
|
18
21
|
--bg-tertiary: #e5e5e7;
|
|
@@ -27,6 +30,11 @@
|
|
|
27
30
|
--error: #ff3b30;
|
|
28
31
|
--selected-bg: #e8f4fd;
|
|
29
32
|
--selected-border: #0071e3;
|
|
33
|
+
|
|
34
|
+
--g-col:rgba(0,113,227,.075);
|
|
35
|
+
--g-edge:rgba(0,113,227,.40);
|
|
36
|
+
--g-base:rgba(0,150,140,.34);
|
|
37
|
+
--g-base-min:rgba(0,150,140,.12);
|
|
30
38
|
}
|
|
31
39
|
|
|
32
40
|
@media (prefers-color-scheme: dark) {
|
|
@@ -42,44 +50,85 @@
|
|
|
42
50
|
--accent-hover: #409cff;
|
|
43
51
|
--selected-bg: rgba(10, 132, 255, 0.15);
|
|
44
52
|
--selected-border: #0a84ff;
|
|
53
|
+
--g-col:rgba(10,132,255,.075);
|
|
54
|
+
--g-edge:rgba(10,132,255,.40);
|
|
45
55
|
}
|
|
46
56
|
}
|
|
47
57
|
|
|
58
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
59
|
+
html, body { height: 100%; overflow: hidden; }
|
|
60
|
+
|
|
48
61
|
body {
|
|
49
62
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
|
|
50
63
|
background: var(--bg-primary);
|
|
51
64
|
color: var(--text-primary);
|
|
52
65
|
display: flex;
|
|
53
66
|
flex-direction: column;
|
|
54
|
-
line-height:
|
|
67
|
+
line-height: var(--lh);
|
|
68
|
+
font-size: 16px;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* ---- scaffold ---- */
|
|
72
|
+
.spread{position:relative;width:100%;}
|
|
73
|
+
.wrap{position:relative;max-width:var(--maxw);margin:0 auto;padding:var(--pad) var(--margin);}
|
|
74
|
+
.grid{display:grid;grid-template-columns:repeat(var(--cols),1fr);
|
|
75
|
+
column-gap:var(--gutter);row-gap:var(--lh);}
|
|
76
|
+
.band{grid-column:1 / -1;display:grid;grid-template-columns:subgrid;
|
|
77
|
+
column-gap:var(--gutter);row-gap:var(--lh);align-items:start;}
|
|
78
|
+
@supports not (grid-template-columns:subgrid){
|
|
79
|
+
.band{grid-template-columns:repeat(var(--cols),1fr);}
|
|
55
80
|
}
|
|
56
81
|
|
|
82
|
+
/* ---- toggle & guides ---- */
|
|
83
|
+
.guides{position:absolute;inset:0;pointer-events:none;z-index:60;opacity:0;
|
|
84
|
+
transition:opacity .26s ease;}
|
|
85
|
+
body.grid-on .guides{opacity:1;}
|
|
86
|
+
.guides .cols{position:absolute;top:0;bottom:0;left:var(--margin);right:var(--margin);
|
|
87
|
+
display:grid;grid-template-columns:repeat(var(--cols),1fr);column-gap:var(--gutter);}
|
|
88
|
+
.guides .col{background:var(--g-col);
|
|
89
|
+
box-shadow:inset 1px 0 0 var(--g-edge),inset -1px 0 0 var(--g-edge);position:relative;}
|
|
90
|
+
.guides .col span{position:absolute;top:32px;left:0;right:0;text-align:center;
|
|
91
|
+
font-family:"Space Mono",monospace;font-size:10px;line-height:1;color:var(--accent);}
|
|
92
|
+
.guides .rows{position:absolute;left:var(--margin);right:var(--margin);top:0;bottom:0;
|
|
93
|
+
background-image:
|
|
94
|
+
repeating-linear-gradient(to bottom,var(--g-base) 0 1px,transparent 1px var(--lh)),
|
|
95
|
+
repeating-linear-gradient(to bottom,var(--g-base-min) 0 1px,transparent 1px var(--bl));}
|
|
96
|
+
.guides .mline{position:absolute;top:0;bottom:0;width:1px;background:var(--g-edge);}
|
|
97
|
+
.guides .mline.l{left:var(--margin);} .guides .mline.r{right:var(--margin);}
|
|
98
|
+
|
|
99
|
+
.toggle{position:fixed;top:18px;right:18px;z-index:200;display:flex;align-items:center;gap:10px;
|
|
100
|
+
background:var(--bg-secondary);color:var(--text-primary);border:1px solid var(--border);cursor:pointer;font-family:"Space Mono",monospace;
|
|
101
|
+
font-size:12px;letter-spacing:.14em;text-transform:uppercase;padding:11px 14px;border-radius:4px;}
|
|
102
|
+
.toggle .dot{width:9px;height:9px;border-radius:50%;background:var(--text-tertiary);}
|
|
103
|
+
body.grid-on .toggle{background:var(--accent);color:#fff;border-color:var(--accent);} body.grid-on .toggle .dot{background:#fff;}
|
|
104
|
+
|
|
57
105
|
/* ===== FRAME STRUCTURE ===== */
|
|
58
106
|
.header {
|
|
59
107
|
background: var(--bg-secondary);
|
|
60
|
-
padding:
|
|
108
|
+
padding: var(--lh) var(--margin);
|
|
61
109
|
display: flex;
|
|
62
110
|
justify-content: space-between;
|
|
63
111
|
align-items: center;
|
|
64
112
|
border-bottom: 1px solid var(--border);
|
|
65
113
|
flex-shrink: 0;
|
|
66
114
|
}
|
|
67
|
-
.header h1 { font-size:
|
|
68
|
-
.header .status { font-size:
|
|
115
|
+
.header h1 { font-size: 16px; font-weight: 500; color: var(--text-secondary); line-height: var(--lh); margin: 0; }
|
|
116
|
+
.header .status { font-size: 12px; color: var(--success); display: flex; align-items: center; gap: 8px; line-height: var(--lh); }
|
|
69
117
|
.header .status::before { content: ''; width: 6px; height: 6px; background: var(--success); border-radius: 50%; }
|
|
70
118
|
|
|
71
|
-
.main { flex: 1; overflow-y: auto; }
|
|
72
|
-
#claude-content {
|
|
119
|
+
.main { flex: 1; overflow-y: auto; position: relative; }
|
|
120
|
+
#claude-content { min-height: 100%; }
|
|
73
121
|
|
|
74
122
|
.indicator-bar {
|
|
75
123
|
background: var(--bg-secondary);
|
|
76
124
|
border-top: 1px solid var(--border);
|
|
77
|
-
padding:
|
|
125
|
+
padding: var(--bl) var(--margin);
|
|
78
126
|
flex-shrink: 0;
|
|
79
127
|
text-align: center;
|
|
128
|
+
line-height: var(--lh);
|
|
80
129
|
}
|
|
81
130
|
.indicator-bar span {
|
|
82
|
-
font-size:
|
|
131
|
+
font-size: 12px;
|
|
83
132
|
color: var(--text-secondary);
|
|
84
133
|
}
|
|
85
134
|
.indicator-bar .selected-text {
|
|
@@ -88,42 +137,43 @@
|
|
|
88
137
|
}
|
|
89
138
|
|
|
90
139
|
/* ===== TYPOGRAPHY ===== */
|
|
91
|
-
h2 { font-size: 1.
|
|
92
|
-
h3 { font-size:
|
|
93
|
-
.subtitle { color: var(--text-secondary); margin-bottom: 1
|
|
94
|
-
.section { margin-bottom:
|
|
95
|
-
.label { font-size:
|
|
140
|
+
h2 { font-size: 24px; line-height: calc(var(--lh) * 1.5); font-weight: 600; margin-bottom: var(--lh); grid-column: 1 / -1; }
|
|
141
|
+
h3 { font-size: 16px; line-height: var(--lh); font-weight: 600; margin-bottom: var(--bl); }
|
|
142
|
+
.subtitle { color: var(--text-secondary); margin-bottom: var(--lh); grid-column: 1 / -1; }
|
|
143
|
+
.section { margin-bottom: calc(var(--lh) * 2); grid-column: 1 / -1; }
|
|
144
|
+
.label { font-size: 12px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: var(--bl); line-height: var(--lh); }
|
|
96
145
|
|
|
97
146
|
/* ===== OPTIONS ===== */
|
|
98
|
-
.options { display:
|
|
147
|
+
.options { display: grid; grid-template-columns: subgrid; grid-column: 1 / -1; row-gap: var(--lh); }
|
|
99
148
|
.option {
|
|
100
149
|
background: var(--bg-secondary);
|
|
101
150
|
border: 2px solid var(--border);
|
|
102
151
|
border-radius: 12px;
|
|
103
|
-
padding:
|
|
152
|
+
padding: calc(var(--lh) - 2px) 1.25rem;
|
|
104
153
|
cursor: pointer;
|
|
105
154
|
transition: all 0.15s ease;
|
|
106
155
|
display: flex;
|
|
107
156
|
align-items: flex-start;
|
|
108
|
-
gap:
|
|
157
|
+
gap: var(--gutter);
|
|
158
|
+
grid-column: span 6; /* Options span 6 cols each */
|
|
109
159
|
}
|
|
110
160
|
.option:hover { border-color: var(--accent); }
|
|
111
161
|
.option.selected { background: var(--selected-bg); border-color: var(--selected-border); }
|
|
112
162
|
.option .letter {
|
|
113
163
|
background: var(--bg-tertiary);
|
|
114
164
|
color: var(--text-secondary);
|
|
115
|
-
width: 1.
|
|
165
|
+
width: calc(var(--lh) * 1.5); height: calc(var(--lh) * 1.5);
|
|
116
166
|
border-radius: 6px;
|
|
117
167
|
display: flex; align-items: center; justify-content: center;
|
|
118
|
-
font-weight: 600; font-size:
|
|
168
|
+
font-weight: 600; font-size: 16px; flex-shrink: 0;
|
|
119
169
|
}
|
|
120
170
|
.option.selected .letter { background: var(--accent); color: white; }
|
|
121
171
|
.option .content { flex: 1; }
|
|
122
|
-
.option .content h3 { font-size:
|
|
123
|
-
.option .content p { color: var(--text-secondary); font-size:
|
|
172
|
+
.option .content h3 { font-size: 16px; margin-bottom: var(--bl); }
|
|
173
|
+
.option .content p { color: var(--text-secondary); font-size: 14px; margin: 0; line-height: var(--lh); }
|
|
124
174
|
|
|
125
175
|
/* ===== CARDS ===== */
|
|
126
|
-
.cards { display: grid; grid-template-columns:
|
|
176
|
+
.cards { display: grid; grid-template-columns: subgrid; grid-column: 1 / -1; row-gap: var(--lh); }
|
|
127
177
|
.card {
|
|
128
178
|
background: var(--bg-secondary);
|
|
129
179
|
border: 1px solid var(--border);
|
|
@@ -131,13 +181,14 @@
|
|
|
131
181
|
overflow: hidden;
|
|
132
182
|
cursor: pointer;
|
|
133
183
|
transition: all 0.15s ease;
|
|
184
|
+
grid-column: span 4; /* Cards span 4 cols each (3 per row) */
|
|
134
185
|
}
|
|
135
186
|
.card:hover { border-color: var(--accent); transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
|
|
136
187
|
.card.selected { border-color: var(--selected-border); border-width: 2px; }
|
|
137
|
-
.card-image { background: var(--bg-tertiary);
|
|
138
|
-
.card-body { padding:
|
|
139
|
-
.card-body h3 { margin-bottom:
|
|
140
|
-
.card-body p { color: var(--text-secondary); font-size: 0
|
|
188
|
+
.card-image { background: var(--bg-tertiary); height: calc(var(--lh) * 6); display: flex; align-items: center; justify-content: center; }
|
|
189
|
+
.card-body { padding: calc(var(--lh) - 1px) var(--gutter); }
|
|
190
|
+
.card-body h3 { margin-bottom: var(--bl); }
|
|
191
|
+
.card-body p { color: var(--text-secondary); font-size: 14px; line-height: var(--lh); margin: 0; }
|
|
141
192
|
|
|
142
193
|
/* ===== MOCKUP CONTAINER ===== */
|
|
143
194
|
.mockup {
|
|
@@ -145,28 +196,30 @@
|
|
|
145
196
|
border: 1px solid var(--border);
|
|
146
197
|
border-radius: 12px;
|
|
147
198
|
overflow: hidden;
|
|
148
|
-
margin-bottom:
|
|
199
|
+
margin-bottom: var(--lh);
|
|
200
|
+
grid-column: 1 / -1;
|
|
149
201
|
}
|
|
150
202
|
.mockup-header {
|
|
151
203
|
background: var(--bg-tertiary);
|
|
152
|
-
padding:
|
|
153
|
-
font-size:
|
|
204
|
+
padding: calc(var(--bl) - 1px) var(--gutter);
|
|
205
|
+
font-size: 12px;
|
|
206
|
+
line-height: var(--lh);
|
|
154
207
|
color: var(--text-secondary);
|
|
155
208
|
border-bottom: 1px solid var(--border);
|
|
156
209
|
}
|
|
157
|
-
.mockup-body { padding:
|
|
210
|
+
.mockup-body { padding: var(--lh) var(--gutter); }
|
|
158
211
|
|
|
159
212
|
/* ===== SPLIT VIEW ===== */
|
|
160
|
-
.split { display: grid; grid-template-columns:
|
|
161
|
-
|
|
213
|
+
.split { display: grid; grid-template-columns: subgrid; grid-column: 1 / -1; }
|
|
214
|
+
.split > div { grid-column: span 6; }
|
|
162
215
|
|
|
163
216
|
/* ===== PROS/CONS ===== */
|
|
164
|
-
.pros-cons { display: grid; grid-template-columns:
|
|
165
|
-
.pros, .cons { background: var(--bg-secondary); border-radius: 8px; padding:
|
|
166
|
-
.pros h4 { color: var(--success); font-size:
|
|
167
|
-
.cons h4 { color: var(--error); font-size:
|
|
168
|
-
.pros ul, .cons ul { margin-left: 1.25rem; font-size:
|
|
169
|
-
.pros li, .cons li { margin-bottom:
|
|
217
|
+
.pros-cons { display: grid; grid-template-columns: subgrid; grid-column: 1 / -1; margin-bottom: var(--lh); }
|
|
218
|
+
.pros, .cons { background: var(--bg-secondary); border-radius: 8px; padding: calc(var(--lh) - 1px) var(--gutter); grid-column: span 6; border: 1px solid var(--border); }
|
|
219
|
+
.pros h4 { color: var(--success); font-size: 14px; margin-bottom: var(--bl); line-height: var(--lh); }
|
|
220
|
+
.cons h4 { color: var(--error); font-size: 14px; margin-bottom: var(--bl); line-height: var(--lh); }
|
|
221
|
+
.pros ul, .cons ul { margin-left: 1.25rem; font-size: 14px; color: var(--text-secondary); }
|
|
222
|
+
.pros li, .cons li { margin-bottom: var(--bl); }
|
|
170
223
|
</style>
|
|
171
224
|
</head>
|
|
172
225
|
<body>
|
|
@@ -176,8 +229,54 @@
|
|
|
176
229
|
</div>
|
|
177
230
|
|
|
178
231
|
<div class="main">
|
|
179
|
-
<div id="claude-content">
|
|
180
|
-
|
|
232
|
+
<div id="claude-content" class="spread">
|
|
233
|
+
<div class="wrap">
|
|
234
|
+
<div class="grid">
|
|
235
|
+
<div class="band section">
|
|
236
|
+
<h2 class="opt-align">Dashboard Template</h2>
|
|
237
|
+
<p class="subtitle">Mockup and structure using the new 12-column Müller-Brockmann grid.</p>
|
|
238
|
+
</div>
|
|
239
|
+
|
|
240
|
+
<div class="band section split">
|
|
241
|
+
<div>
|
|
242
|
+
<h3 class="opt-align">Split Left (6 cols)</h3>
|
|
243
|
+
<p>Aligned precisely to the grid. All baselines lock to 8px.</p>
|
|
244
|
+
</div>
|
|
245
|
+
<div>
|
|
246
|
+
<h3 class="opt-align">Split Right (6 cols)</h3>
|
|
247
|
+
<p>The gap between is precisely one gutter (24px).</p>
|
|
248
|
+
</div>
|
|
249
|
+
</div>
|
|
250
|
+
|
|
251
|
+
<div class="band section cards">
|
|
252
|
+
<div class="card">
|
|
253
|
+
<div class="card-image">Img 1</div>
|
|
254
|
+
<div class="card-body">
|
|
255
|
+
<h3>Card 1 (4 cols)</h3>
|
|
256
|
+
<p>Three cards fit perfectly in 12 columns.</p>
|
|
257
|
+
</div>
|
|
258
|
+
</div>
|
|
259
|
+
<div class="card">
|
|
260
|
+
<div class="card-image">Img 2</div>
|
|
261
|
+
<div class="card-body">
|
|
262
|
+
<h3>Card 2 (4 cols)</h3>
|
|
263
|
+
<p>Aligned on the baseline.</p>
|
|
264
|
+
</div>
|
|
265
|
+
</div>
|
|
266
|
+
<div class="card selected">
|
|
267
|
+
<div class="card-image">Img 3</div>
|
|
268
|
+
<div class="card-body">
|
|
269
|
+
<h3>Card 3 (4 cols)</h3>
|
|
270
|
+
<p>This card is selected.</p>
|
|
271
|
+
</div>
|
|
272
|
+
</div>
|
|
273
|
+
</div>
|
|
274
|
+
<!-- GRID GUIDES -->
|
|
275
|
+
<div class="guides" aria-hidden="true">
|
|
276
|
+
<div class="cols"></div><div class="rows"></div>
|
|
277
|
+
<div class="mline l"></div><div class="mline r"></div>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
181
280
|
</div>
|
|
182
281
|
</div>
|
|
183
282
|
|
|
@@ -185,5 +284,42 @@
|
|
|
185
284
|
<span id="indicator-text">Interact with the dashboard, then return to the terminal</span>
|
|
186
285
|
</div>
|
|
187
286
|
|
|
287
|
+
<button id="gridToggle" class="toggle"><span class="dot"></span> <span class="lbl">Show grid</span> <kbd>G</kbd></button>
|
|
288
|
+
|
|
289
|
+
<script>
|
|
290
|
+
/* ===== GRID SCRIPT ===== */
|
|
291
|
+
var btn=document.getElementById('gridToggle');
|
|
292
|
+
function setGrid(on){document.body.classList.toggle('grid-on',on);
|
|
293
|
+
if(btn){btn.setAttribute('aria-pressed',on?'true':'false');
|
|
294
|
+
var l=btn.querySelector('.lbl'); if(l) l.textContent=on?'Hide grid':'Show grid';}}
|
|
295
|
+
if(btn) btn.addEventListener('click',function(){setGrid(!document.body.classList.contains('grid-on'));});
|
|
296
|
+
document.addEventListener('keydown',function(e){
|
|
297
|
+
if((e.key==='g'||e.key==='G')&&!e.metaKey&&!e.ctrlKey&&!e.altKey){
|
|
298
|
+
setGrid(!document.body.classList.contains('grid-on'));}});
|
|
299
|
+
|
|
300
|
+
document.querySelectorAll('.guides .cols').forEach(function(h){
|
|
301
|
+
var n=getComputedStyle(document.documentElement).getPropertyValue('--cols').trim()||'12';
|
|
302
|
+
for(var i=1;i<=parseInt(n,10);i++){var c=document.createElement('div');c.className='col';
|
|
303
|
+
var s=document.createElement('span');s.textContent=i;c.appendChild(s);h.appendChild(c);}});
|
|
304
|
+
|
|
305
|
+
(function(){
|
|
306
|
+
var cvs=document.createElement('canvas'),ctx=cvs.getContext('2d');
|
|
307
|
+
var sel='.opt-align';
|
|
308
|
+
function align(){
|
|
309
|
+
document.querySelectorAll(sel).forEach(function(el){
|
|
310
|
+
el.style.marginLeft='0px';
|
|
311
|
+
var cs=getComputedStyle(el),ch=(el.textContent||'').trim().charAt(0); if(!ch) return;
|
|
312
|
+
if(cs.textTransform==='uppercase') ch=ch.toUpperCase();
|
|
313
|
+
ctx.font=cs.fontStyle+' '+cs.fontWeight+' '+cs.fontSize+' '+cs.fontFamily;
|
|
314
|
+
ctx.textAlign='left';
|
|
315
|
+
var abl=ctx.measureText(ch).actualBoundingBoxLeft;
|
|
316
|
+
if(isFinite(abl)) el.style.marginLeft=abl.toFixed(2)+'px';
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
if(document.fonts&&document.fonts.ready){document.fonts.ready.then(align);}
|
|
320
|
+
align();
|
|
321
|
+
var t;window.addEventListener('resize',function(){clearTimeout(t);t=setTimeout(align,120);});
|
|
322
|
+
})();
|
|
323
|
+
</script>
|
|
188
324
|
</body>
|
|
189
325
|
</html>
|