@a2uicatalog/mcp 0.1.1 → 0.2.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/cli-test.mjs +54 -0
- package/cli.mjs +163 -0
- package/data/atoms-index.json +55 -0
- package/data/spec.json +219 -1
- package/package.json +35 -8
package/cli-test.mjs
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// cli-test.mjs — the CLI must agree with the server it fronts.
|
|
2
|
+
//
|
|
3
|
+
// The interesting failure is not "does it run" but "does it tell the truth":
|
|
4
|
+
// validate reads the BUNDLED vocabulary snapshot while render asks the live
|
|
5
|
+
// endpoint, so the two drift apart the moment data/ goes stale. That happened
|
|
6
|
+
// on the first run of this CLI — validate reported a payload clean that the
|
|
7
|
+
// server correctly refused — which is why the agreement is asserted here
|
|
8
|
+
// rather than assumed.
|
|
9
|
+
import { execFileSync } from 'node:child_process';
|
|
10
|
+
import { writeFileSync, unlinkSync } from 'node:fs';
|
|
11
|
+
|
|
12
|
+
const run = (args, ok = [0]) => {
|
|
13
|
+
try { return { out: execFileSync('node', ['cli.mjs', ...args], { encoding: 'utf8' }), code: 0 }; }
|
|
14
|
+
catch (e) {
|
|
15
|
+
if (!ok.includes(e.status)) throw new Error(`a2ui ${args.join(' ')} exited ${e.status}\n${e.stderr}`);
|
|
16
|
+
return { out: (e.stdout || '') + (e.stderr || ''), code: e.status };
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
let n = 0;
|
|
20
|
+
const t = (name, fn) => { fn(); n++; console.log(` ok ${name}`); };
|
|
21
|
+
|
|
22
|
+
const f = '/tmp/a2ui-cli-test.json';
|
|
23
|
+
writeFileSync(f, JSON.stringify({ blocks: [{ type: 'heading', text: 'x' }, { type: 'quiz_set', questions: [] }] }));
|
|
24
|
+
|
|
25
|
+
t('help lists every command', () => {
|
|
26
|
+
const { out } = run(['help']);
|
|
27
|
+
for (const c of ['render', 'validate', 'atoms', 'surfaces'])
|
|
28
|
+
if (!out.includes(c)) throw new Error(`help omits ${c}`);
|
|
29
|
+
});
|
|
30
|
+
t('validate passes a clean payload', () => {
|
|
31
|
+
writeFileSync(f, JSON.stringify({ blocks: [{ type: 'heading', text: 'x' }] }));
|
|
32
|
+
if (run(['validate', f]).code !== 0) throw new Error('clean payload rejected');
|
|
33
|
+
});
|
|
34
|
+
t('validate rejects an unknown atom', () => {
|
|
35
|
+
writeFileSync(f, JSON.stringify({ blocks: [{ type: 'not_an_atom' }] }));
|
|
36
|
+
if (run(['validate', f], [0, 1]).code !== 1) throw new Error('unknown atom accepted');
|
|
37
|
+
});
|
|
38
|
+
t('validate honours the surface declaration', () => {
|
|
39
|
+
writeFileSync(f, JSON.stringify({ blocks: [{ type: 'quiz_set', questions: [] }] }));
|
|
40
|
+
const r = run(['validate', f, '--surface', 'web'], [0, 1]);
|
|
41
|
+
if (r.code !== 1 || !r.out.includes('incompatible'))
|
|
42
|
+
throw new Error('quiz_set accepted on web — bundled vocabulary is stale (npm run sync-data)');
|
|
43
|
+
});
|
|
44
|
+
t('surfaces reports declared incompatibility', () => {
|
|
45
|
+
if (!run(['surfaces', 'quiz_set']).out.includes('incompatible'))
|
|
46
|
+
throw new Error('surfaces omits incompatible_on');
|
|
47
|
+
});
|
|
48
|
+
t('atoms filters by surface', () => {
|
|
49
|
+
const all = run(['atoms']).out.split('\n').length;
|
|
50
|
+
const email = run(['atoms', '--surface', 'email']).out.split('\n').length;
|
|
51
|
+
if (!(email < all)) throw new Error('--surface did not narrow the list');
|
|
52
|
+
});
|
|
53
|
+
unlinkSync(f);
|
|
54
|
+
console.log(`\n${n} CLI checks passed`);
|
package/cli.mjs
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// cli.mjs — the A2UI command line.
|
|
3
|
+
//
|
|
4
|
+
// The on-ramp for someone who wants the vocabulary and none of the protocol:
|
|
5
|
+
// no MCP client, no connector, no deployment, no account. Compose a payload
|
|
6
|
+
// against spec.json, render it, get HTML.
|
|
7
|
+
//
|
|
8
|
+
// npx @a2uicatalog/mcp render page.json > page.html
|
|
9
|
+
// npx @a2uicatalog/mcp validate page.json
|
|
10
|
+
// npx @a2uicatalog/mcp atoms --surface email
|
|
11
|
+
// npx @a2uicatalog/mcp surfaces quiz_set
|
|
12
|
+
//
|
|
13
|
+
// ZERO DEPENDENCIES. Node 18+ has fetch built in, and the vocabulary ships in
|
|
14
|
+
// data/ so validate and atoms work with no network at all. Only `render`
|
|
15
|
+
// leaves the machine, and only to the public endpoint.
|
|
16
|
+
//
|
|
17
|
+
// This file exists because package.json has described this package as
|
|
18
|
+
// "CLI + local MCP server" since 0.1.0 while `bin` pointed at the stdio MCP
|
|
19
|
+
// server and no command line existed. Same class of overclaim the catalogue
|
|
20
|
+
// spent 2026-08-02 removing from its own schema; the honest fix is to build
|
|
21
|
+
// the thing that was advertised.
|
|
22
|
+
|
|
23
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
24
|
+
import { fileURLToPath } from 'node:url';
|
|
25
|
+
import { dirname, join } from 'node:path';
|
|
26
|
+
|
|
27
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
28
|
+
const BASE = process.env.A2UI_BASE || 'https://a2uicatalog.ai';
|
|
29
|
+
const KEY = process.env.A2UI_RENDER_KEY || '';
|
|
30
|
+
|
|
31
|
+
const die = (msg, code = 1) => { process.stderr.write(`a2ui: ${msg}\n`); process.exit(code); };
|
|
32
|
+
|
|
33
|
+
function loadSpec() {
|
|
34
|
+
for (const p of [join(HERE, 'data', 'spec.json'), join(HERE, '..', 'public', 'spec.json')]) {
|
|
35
|
+
if (existsSync(p)) return JSON.parse(readFileSync(p, 'utf8'));
|
|
36
|
+
}
|
|
37
|
+
die('vocabulary not found — reinstall the package, or run from a repo checkout');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readPayload(file) {
|
|
41
|
+
const raw = file && file !== '-' ? readFileSync(file, 'utf8') : readFileSync(0, 'utf8');
|
|
42
|
+
let p;
|
|
43
|
+
try { p = JSON.parse(raw); } catch (e) { die(`${file || 'stdin'} is not valid JSON: ${e.message}`); }
|
|
44
|
+
return Array.isArray(p) ? { blocks: p } : p;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Walk nested blocks the way the render endpoint does, so validate sees the
|
|
48
|
+
// same atoms the server will.
|
|
49
|
+
function collect(blocks, out = new Set(), depth = 0) {
|
|
50
|
+
if (depth > 20 || !Array.isArray(blocks)) return out;
|
|
51
|
+
for (const b of blocks) {
|
|
52
|
+
if (!b || typeof b !== 'object') continue;
|
|
53
|
+
const t = b.component || b.type;
|
|
54
|
+
if (typeof t === 'string') out.add(t);
|
|
55
|
+
for (const v of Object.values(b)) {
|
|
56
|
+
if (Array.isArray(v)) collect(v.filter((x) => x && typeof x === 'object'), out, depth + 1);
|
|
57
|
+
else if (v && typeof v === 'object') collect([v], out, depth + 1);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const CMD = {
|
|
64
|
+
async render(args) {
|
|
65
|
+
const surface = takeFlag(args, '--surface');
|
|
66
|
+
const payload = readPayload(args[0]);
|
|
67
|
+
const url = `${BASE}/api/render${surface ? `?surface=${encodeURIComponent(surface)}` : ''}`;
|
|
68
|
+
const res = await fetch(url, {
|
|
69
|
+
method: 'POST',
|
|
70
|
+
headers: { 'Content-Type': 'application/json', ...(KEY ? { 'x-a2ui-render-key': KEY } : {}) },
|
|
71
|
+
body: JSON.stringify(payload),
|
|
72
|
+
});
|
|
73
|
+
const body = await res.text();
|
|
74
|
+
if (!res.ok) die(`render failed (${res.status}): ${body.slice(0, 300)}`);
|
|
75
|
+
// Degradation is reported on stderr so stdout stays pipeable to a file.
|
|
76
|
+
for (const [h, label] of [['x-a2ui-incompatible', 'omitted (incompatible)'],
|
|
77
|
+
['x-a2ui-degraded', 'degraded'],
|
|
78
|
+
['x-a2ui-unpublished', 'not published']]) {
|
|
79
|
+
const v = res.headers.get(h);
|
|
80
|
+
if (v) process.stderr.write(`a2ui: ${label} on ${surface || 'this surface'}: ${v}\n`);
|
|
81
|
+
}
|
|
82
|
+
process.stdout.write(body);
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
validate(args) {
|
|
86
|
+
const spec = loadSpec();
|
|
87
|
+
const known = new Map((spec.atoms || []).map((a) => [a.type, a]));
|
|
88
|
+
const surface = takeFlag(args, '--surface');
|
|
89
|
+
const payload = readPayload(args[0]);
|
|
90
|
+
if (!Array.isArray(payload.blocks) || !payload.blocks.length) die('payload has no blocks');
|
|
91
|
+
const used = [...collect(payload.blocks)];
|
|
92
|
+
let bad = 0;
|
|
93
|
+
for (const t of used) {
|
|
94
|
+
const a = known.get(t);
|
|
95
|
+
if (!a) { console.error(` unknown atom ${t}`); bad++; continue; }
|
|
96
|
+
if (!surface) continue;
|
|
97
|
+
const s = a.surfaces || {};
|
|
98
|
+
if ((s.incompatible_on || []).some((x) => x.surface === surface)) {
|
|
99
|
+
console.error(` incompatible ${t} on ${surface}`); bad++;
|
|
100
|
+
} else if ((s.degraded_on || []).some((x) => x.surface === surface)) {
|
|
101
|
+
console.error(` degraded ${t} on ${surface}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
console.log(`${used.length} atom(s) checked${surface ? ` for ${surface}` : ''}: ` +
|
|
105
|
+
`${bad ? `${bad} problem(s)` : 'all valid'}`);
|
|
106
|
+
process.exit(bad ? 1 : 0);
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
atoms(args) {
|
|
110
|
+
const spec = loadSpec();
|
|
111
|
+
const surface = takeFlag(args, '--surface');
|
|
112
|
+
const grep = args[0];
|
|
113
|
+
let list = spec.atoms || [];
|
|
114
|
+
if (surface) list = list.filter((a) => ((a.surfaces || {}).works_on || []).includes(surface));
|
|
115
|
+
if (grep) list = list.filter((a) => a.type.includes(grep) ||
|
|
116
|
+
(a.compact_description || '').toLowerCase().includes(grep.toLowerCase()));
|
|
117
|
+
for (const a of list) console.log(`${a.type.padEnd(28)} ${a.compact_description || ''}`);
|
|
118
|
+
console.error(`\n${list.length} atom(s)${surface ? ` on ${surface}` : ''}`);
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
surfaces(args) {
|
|
122
|
+
const t = args[0] || die('usage: a2ui surfaces <atom>');
|
|
123
|
+
const a = (loadSpec().atoms || []).find((x) => x.type === t) || die(`unknown atom '${t}'`);
|
|
124
|
+
const s = a.surfaces || {};
|
|
125
|
+
console.log(`${t} — ${a.compact_description || ''}\n`);
|
|
126
|
+
for (const x of s.works_on || []) console.log(` works ${x}`);
|
|
127
|
+
for (const d of s.degraded_on || []) console.log(` degraded ${d.surface} ${d.note || ''}`);
|
|
128
|
+
for (const d of s.incompatible_on || []) console.log(` incompatible ${d.surface} ${d.reason || ''}`);
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
help() {
|
|
132
|
+
process.stdout.write(`a2ui — the A2UI Atomic Catalog command line
|
|
133
|
+
|
|
134
|
+
render <file|-> [--surface S] payload in, HTML on stdout
|
|
135
|
+
validate <file|-> [--surface S] check atoms exist and are supported; exit 1 if not
|
|
136
|
+
atoms [match] [--surface S] browse the vocabulary
|
|
137
|
+
surfaces <atom> where one atom works, degrades, or cannot go
|
|
138
|
+
|
|
139
|
+
Surfaces for --surface: web · mcp-apps · google-apps-script-web · google-meet-stage
|
|
140
|
+
|
|
141
|
+
A2UI_BASE override the endpoint (default https://a2uicatalog.ai)
|
|
142
|
+
A2UI_RENDER_KEY unmetered rendering, if you have a key
|
|
143
|
+
|
|
144
|
+
validate and atoms are fully offline — the vocabulary ships with the package.
|
|
145
|
+
Only render makes a network call. No account, no API key, no MCP client.
|
|
146
|
+
|
|
147
|
+
npx @a2uicatalog/mcp render page.json > page.html
|
|
148
|
+
`);
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
function takeFlag(args, name) {
|
|
153
|
+
const i = args.indexOf(name);
|
|
154
|
+
if (i === -1) return null;
|
|
155
|
+
const v = args[i + 1];
|
|
156
|
+
args.splice(i, 2);
|
|
157
|
+
return v;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const [cmd, ...rest] = process.argv.slice(2);
|
|
161
|
+
const fn = CMD[cmd] || (cmd === undefined || cmd === '--help' || cmd === '-h' ? CMD.help : null);
|
|
162
|
+
if (!fn) die(`unknown command '${cmd}' — try: a2ui help`);
|
|
163
|
+
await fn(rest);
|
package/data/atoms-index.json
CHANGED
|
@@ -3324,6 +3324,7 @@
|
|
|
3324
3324
|
"type": "paragraph",
|
|
3325
3325
|
"compact": "prose paragraph (GAS alias for body)",
|
|
3326
3326
|
"surfaces": [
|
|
3327
|
+
"web",
|
|
3327
3328
|
"google-apps-script-web",
|
|
3328
3329
|
"mcp-apps"
|
|
3329
3330
|
]
|
|
@@ -3332,6 +3333,7 @@
|
|
|
3332
3333
|
"type": "text_block",
|
|
3333
3334
|
"compact": "plain text block",
|
|
3334
3335
|
"surfaces": [
|
|
3336
|
+
"web",
|
|
3335
3337
|
"google-apps-script-web",
|
|
3336
3338
|
"mcp-apps"
|
|
3337
3339
|
]
|
|
@@ -3340,6 +3342,7 @@
|
|
|
3340
3342
|
"type": "blockquote",
|
|
3341
3343
|
"compact": "styled pull-quote with attribution",
|
|
3342
3344
|
"surfaces": [
|
|
3345
|
+
"web",
|
|
3343
3346
|
"google-apps-script-web",
|
|
3344
3347
|
"mcp-apps"
|
|
3345
3348
|
]
|
|
@@ -3348,6 +3351,7 @@
|
|
|
3348
3351
|
"type": "spacer",
|
|
3349
3352
|
"compact": "vertical whitespace gap",
|
|
3350
3353
|
"surfaces": [
|
|
3354
|
+
"web",
|
|
3351
3355
|
"google-apps-script-web",
|
|
3352
3356
|
"mcp-apps"
|
|
3353
3357
|
]
|
|
@@ -3356,6 +3360,7 @@
|
|
|
3356
3360
|
"type": "tag_chip",
|
|
3357
3361
|
"compact": "inline tag chip",
|
|
3358
3362
|
"surfaces": [
|
|
3363
|
+
"web",
|
|
3359
3364
|
"google-apps-script-web",
|
|
3360
3365
|
"mcp-apps"
|
|
3361
3366
|
]
|
|
@@ -3364,6 +3369,7 @@
|
|
|
3364
3369
|
"type": "badge",
|
|
3365
3370
|
"compact": "inline badge pill",
|
|
3366
3371
|
"surfaces": [
|
|
3372
|
+
"web",
|
|
3367
3373
|
"google-apps-script-web",
|
|
3368
3374
|
"mcp-apps"
|
|
3369
3375
|
]
|
|
@@ -3372,6 +3378,7 @@
|
|
|
3372
3378
|
"type": "inline_code",
|
|
3373
3379
|
"compact": "monospace inline code span",
|
|
3374
3380
|
"surfaces": [
|
|
3381
|
+
"web",
|
|
3375
3382
|
"google-apps-script-web",
|
|
3376
3383
|
"mcp-apps"
|
|
3377
3384
|
]
|
|
@@ -3380,6 +3387,7 @@
|
|
|
3380
3387
|
"type": "code_block",
|
|
3381
3388
|
"compact": "syntax-highlighted code block",
|
|
3382
3389
|
"surfaces": [
|
|
3390
|
+
"web",
|
|
3383
3391
|
"google-apps-script-web",
|
|
3384
3392
|
"mcp-apps"
|
|
3385
3393
|
]
|
|
@@ -3388,6 +3396,7 @@
|
|
|
3388
3396
|
"type": "link_button",
|
|
3389
3397
|
"compact": "text hyperlink button",
|
|
3390
3398
|
"surfaces": [
|
|
3399
|
+
"web",
|
|
3391
3400
|
"google-apps-script-web",
|
|
3392
3401
|
"mcp-apps"
|
|
3393
3402
|
]
|
|
@@ -3396,6 +3405,7 @@
|
|
|
3396
3405
|
"type": "cta_button",
|
|
3397
3406
|
"compact": "call-to-action button",
|
|
3398
3407
|
"surfaces": [
|
|
3408
|
+
"web",
|
|
3399
3409
|
"google-apps-script-web",
|
|
3400
3410
|
"mcp-apps"
|
|
3401
3411
|
]
|
|
@@ -3414,6 +3424,7 @@
|
|
|
3414
3424
|
"type": "info_card",
|
|
3415
3425
|
"compact": "simple info card with title and body",
|
|
3416
3426
|
"surfaces": [
|
|
3427
|
+
"web",
|
|
3417
3428
|
"google-apps-script-web",
|
|
3418
3429
|
"mcp-apps"
|
|
3419
3430
|
]
|
|
@@ -3438,6 +3449,7 @@
|
|
|
3438
3449
|
"type": "dark_hero",
|
|
3439
3450
|
"compact": "dark hero banner with gradient and CTA",
|
|
3440
3451
|
"surfaces": [
|
|
3452
|
+
"web",
|
|
3441
3453
|
"google-apps-script-web",
|
|
3442
3454
|
"mcp-apps"
|
|
3443
3455
|
]
|
|
@@ -3446,6 +3458,7 @@
|
|
|
3446
3458
|
"type": "glowing_stat",
|
|
3447
3459
|
"compact": "neon-glow stat number on dark card",
|
|
3448
3460
|
"surfaces": [
|
|
3461
|
+
"web",
|
|
3449
3462
|
"google-apps-script-web",
|
|
3450
3463
|
"mcp-apps"
|
|
3451
3464
|
]
|
|
@@ -3454,6 +3467,7 @@
|
|
|
3454
3467
|
"type": "glass_card",
|
|
3455
3468
|
"compact": "frosted-glass card with blur backdrop — dark-theme highlight box",
|
|
3456
3469
|
"surfaces": [
|
|
3470
|
+
"web",
|
|
3457
3471
|
"google-apps-script-web",
|
|
3458
3472
|
"mcp-apps"
|
|
3459
3473
|
]
|
|
@@ -3462,6 +3476,7 @@
|
|
|
3462
3476
|
"type": "gradient_border_card",
|
|
3463
3477
|
"compact": "animated gradient border card",
|
|
3464
3478
|
"surfaces": [
|
|
3479
|
+
"web",
|
|
3465
3480
|
"google-apps-script-web",
|
|
3466
3481
|
"mcp-apps"
|
|
3467
3482
|
]
|
|
@@ -3470,6 +3485,7 @@
|
|
|
3470
3485
|
"type": "floating_orbs",
|
|
3471
3486
|
"compact": "decorative blurred colour orbs background",
|
|
3472
3487
|
"surfaces": [
|
|
3488
|
+
"web",
|
|
3473
3489
|
"google-apps-script-web",
|
|
3474
3490
|
"mcp-apps"
|
|
3475
3491
|
]
|
|
@@ -3486,6 +3502,7 @@
|
|
|
3486
3502
|
"type": "dark_feature_grid",
|
|
3487
3503
|
"compact": "dark-theme feature grid with icons",
|
|
3488
3504
|
"surfaces": [
|
|
3505
|
+
"web",
|
|
3489
3506
|
"google-apps-script-web",
|
|
3490
3507
|
"mcp-apps"
|
|
3491
3508
|
]
|
|
@@ -3494,6 +3511,7 @@
|
|
|
3494
3511
|
"type": "dark_divider",
|
|
3495
3512
|
"compact": "dark-theme horizontal divider",
|
|
3496
3513
|
"surfaces": [
|
|
3514
|
+
"web",
|
|
3497
3515
|
"google-apps-script-web",
|
|
3498
3516
|
"mcp-apps"
|
|
3499
3517
|
]
|
|
@@ -3510,6 +3528,7 @@
|
|
|
3510
3528
|
"type": "depth_stack",
|
|
3511
3529
|
"compact": "stacked cards with depth parallax",
|
|
3512
3530
|
"surfaces": [
|
|
3531
|
+
"web",
|
|
3513
3532
|
"google-apps-script-web",
|
|
3514
3533
|
"mcp-apps"
|
|
3515
3534
|
]
|
|
@@ -3526,6 +3545,7 @@
|
|
|
3526
3545
|
"type": "scroll_trigger",
|
|
3527
3546
|
"compact": "scroll-triggered animated reveal",
|
|
3528
3547
|
"surfaces": [
|
|
3548
|
+
"web",
|
|
3529
3549
|
"google-apps-script-web",
|
|
3530
3550
|
"mcp-apps"
|
|
3531
3551
|
]
|
|
@@ -3534,6 +3554,7 @@
|
|
|
3534
3554
|
"type": "flow_connector",
|
|
3535
3555
|
"compact": "animated beam connector between two or more nodes",
|
|
3536
3556
|
"surfaces": [
|
|
3557
|
+
"web",
|
|
3537
3558
|
"google-apps-script-web",
|
|
3538
3559
|
"mcp-apps"
|
|
3539
3560
|
]
|
|
@@ -3542,6 +3563,7 @@
|
|
|
3542
3563
|
"type": "live_metric",
|
|
3543
3564
|
"compact": "animated counting number (alias for animated_counter)",
|
|
3544
3565
|
"surfaces": [
|
|
3566
|
+
"web",
|
|
3545
3567
|
"google-apps-script-web",
|
|
3546
3568
|
"mcp-apps"
|
|
3547
3569
|
]
|
|
@@ -3550,6 +3572,7 @@
|
|
|
3550
3572
|
"type": "deadline_ticker",
|
|
3551
3573
|
"compact": "countdown timer to a target date (alias)",
|
|
3552
3574
|
"surfaces": [
|
|
3575
|
+
"web",
|
|
3553
3576
|
"google-apps-script-web",
|
|
3554
3577
|
"mcp-apps"
|
|
3555
3578
|
]
|
|
@@ -3558,6 +3581,7 @@
|
|
|
3558
3581
|
"type": "pattern_background",
|
|
3559
3582
|
"compact": "dot-grid pattern background (alias)",
|
|
3560
3583
|
"surfaces": [
|
|
3584
|
+
"web",
|
|
3561
3585
|
"google-apps-script-web",
|
|
3562
3586
|
"mcp-apps"
|
|
3563
3587
|
]
|
|
@@ -3566,6 +3590,7 @@
|
|
|
3566
3590
|
"type": "glitch_text",
|
|
3567
3591
|
"compact": "RGB-split glitch-effect headline",
|
|
3568
3592
|
"surfaces": [
|
|
3593
|
+
"web",
|
|
3569
3594
|
"google-apps-script-web",
|
|
3570
3595
|
"mcp-apps"
|
|
3571
3596
|
]
|
|
@@ -3598,6 +3623,7 @@
|
|
|
3598
3623
|
"type": "floating_particles",
|
|
3599
3624
|
"compact": "floating particles background (canvas placeholder)",
|
|
3600
3625
|
"surfaces": [
|
|
3626
|
+
"web",
|
|
3601
3627
|
"google-apps-script-web",
|
|
3602
3628
|
"mcp-apps"
|
|
3603
3629
|
]
|
|
@@ -3606,6 +3632,7 @@
|
|
|
3606
3632
|
"type": "parallax_section",
|
|
3607
3633
|
"compact": "parallax scroll section (canvas placeholder)",
|
|
3608
3634
|
"surfaces": [
|
|
3635
|
+
"web",
|
|
3609
3636
|
"google-apps-script-web",
|
|
3610
3637
|
"mcp-apps"
|
|
3611
3638
|
]
|
|
@@ -3614,6 +3641,7 @@
|
|
|
3614
3641
|
"type": "scroll_progress",
|
|
3615
3642
|
"compact": "fixed scroll-progress bar at page top",
|
|
3616
3643
|
"surfaces": [
|
|
3644
|
+
"web",
|
|
3617
3645
|
"google-apps-script-web",
|
|
3618
3646
|
"mcp-apps"
|
|
3619
3647
|
]
|
|
@@ -3622,6 +3650,7 @@
|
|
|
3622
3650
|
"type": "live_clock",
|
|
3623
3651
|
"compact": "live ticking clock widget",
|
|
3624
3652
|
"surfaces": [
|
|
3653
|
+
"web",
|
|
3625
3654
|
"google-apps-script-web",
|
|
3626
3655
|
"mcp-apps"
|
|
3627
3656
|
]
|
|
@@ -3630,6 +3659,7 @@
|
|
|
3630
3659
|
"type": "decision_tree",
|
|
3631
3660
|
"compact": "interactive collapsible decision tree",
|
|
3632
3661
|
"surfaces": [
|
|
3662
|
+
"web",
|
|
3633
3663
|
"google-apps-script-web",
|
|
3634
3664
|
"mcp-apps"
|
|
3635
3665
|
]
|
|
@@ -3638,6 +3668,7 @@
|
|
|
3638
3668
|
"type": "step_reveal_sequence",
|
|
3639
3669
|
"compact": "tabbed step-by-step sequence",
|
|
3640
3670
|
"surfaces": [
|
|
3671
|
+
"web",
|
|
3641
3672
|
"google-apps-script-web",
|
|
3642
3673
|
"mcp-apps"
|
|
3643
3674
|
]
|
|
@@ -3654,6 +3685,7 @@
|
|
|
3654
3685
|
"type": "tooltip_glossary",
|
|
3655
3686
|
"compact": "glossary with hover tooltips",
|
|
3656
3687
|
"surfaces": [
|
|
3688
|
+
"web",
|
|
3657
3689
|
"google-apps-script-web",
|
|
3658
3690
|
"mcp-apps"
|
|
3659
3691
|
]
|
|
@@ -3662,6 +3694,7 @@
|
|
|
3662
3694
|
"type": "focus_lens",
|
|
3663
3695
|
"compact": "spotlight focus lens on blurred background",
|
|
3664
3696
|
"surfaces": [
|
|
3697
|
+
"web",
|
|
3665
3698
|
"google-apps-script-web",
|
|
3666
3699
|
"mcp-apps"
|
|
3667
3700
|
]
|
|
@@ -3678,6 +3711,7 @@
|
|
|
3678
3711
|
"type": "stagger_list",
|
|
3679
3712
|
"compact": "stagger-animated list of items",
|
|
3680
3713
|
"surfaces": [
|
|
3714
|
+
"web",
|
|
3681
3715
|
"google-apps-script-web",
|
|
3682
3716
|
"mcp-apps"
|
|
3683
3717
|
]
|
|
@@ -3686,6 +3720,7 @@
|
|
|
3686
3720
|
"type": "liquid_button",
|
|
3687
3721
|
"compact": "liquid morphing hover button",
|
|
3688
3722
|
"surfaces": [
|
|
3723
|
+
"web",
|
|
3689
3724
|
"google-apps-script-web",
|
|
3690
3725
|
"mcp-apps"
|
|
3691
3726
|
]
|
|
@@ -3694,6 +3729,7 @@
|
|
|
3694
3729
|
"type": "highlight_sweep",
|
|
3695
3730
|
"compact": "animated highlight sweep text",
|
|
3696
3731
|
"surfaces": [
|
|
3732
|
+
"web",
|
|
3697
3733
|
"google-apps-script-web",
|
|
3698
3734
|
"mcp-apps"
|
|
3699
3735
|
]
|
|
@@ -3702,6 +3738,7 @@
|
|
|
3702
3738
|
"type": "progress_reveal",
|
|
3703
3739
|
"compact": "scroll-triggered animated progress bar",
|
|
3704
3740
|
"surfaces": [
|
|
3741
|
+
"web",
|
|
3705
3742
|
"google-apps-script-web",
|
|
3706
3743
|
"mcp-apps"
|
|
3707
3744
|
]
|
|
@@ -3710,6 +3747,7 @@
|
|
|
3710
3747
|
"type": "big_reveal",
|
|
3711
3748
|
"compact": "spring-animation big number or word reveal",
|
|
3712
3749
|
"surfaces": [
|
|
3750
|
+
"web",
|
|
3713
3751
|
"google-apps-script-web",
|
|
3714
3752
|
"mcp-apps"
|
|
3715
3753
|
]
|
|
@@ -3718,6 +3756,7 @@
|
|
|
3718
3756
|
"type": "kinetic_headline",
|
|
3719
3757
|
"compact": "word-by-word kinetic headline animation",
|
|
3720
3758
|
"surfaces": [
|
|
3759
|
+
"web",
|
|
3721
3760
|
"google-apps-script-web",
|
|
3722
3761
|
"mcp-apps"
|
|
3723
3762
|
]
|
|
@@ -3726,6 +3765,7 @@
|
|
|
3726
3765
|
"type": "text_reveal_mask",
|
|
3727
3766
|
"compact": "clip-path text reveal mask animation",
|
|
3728
3767
|
"surfaces": [
|
|
3768
|
+
"web",
|
|
3729
3769
|
"google-apps-script-web",
|
|
3730
3770
|
"mcp-apps"
|
|
3731
3771
|
]
|
|
@@ -3734,6 +3774,7 @@
|
|
|
3734
3774
|
"type": "split_reveal",
|
|
3735
3775
|
"compact": "split-panel reveal animation",
|
|
3736
3776
|
"surfaces": [
|
|
3777
|
+
"web",
|
|
3737
3778
|
"google-apps-script-web",
|
|
3738
3779
|
"mcp-apps"
|
|
3739
3780
|
]
|
|
@@ -3742,6 +3783,7 @@
|
|
|
3742
3783
|
"type": "mesh_gradient",
|
|
3743
3784
|
"compact": "dark card with radial mesh gradient background",
|
|
3744
3785
|
"surfaces": [
|
|
3786
|
+
"web",
|
|
3745
3787
|
"google-apps-script-web",
|
|
3746
3788
|
"mcp-apps"
|
|
3747
3789
|
]
|
|
@@ -3750,6 +3792,7 @@
|
|
|
3750
3792
|
"type": "stripe_background",
|
|
3751
3793
|
"compact": "animated diagonal stripe background card",
|
|
3752
3794
|
"surfaces": [
|
|
3795
|
+
"web",
|
|
3753
3796
|
"google-apps-script-web",
|
|
3754
3797
|
"mcp-apps"
|
|
3755
3798
|
]
|
|
@@ -3774,6 +3817,7 @@
|
|
|
3774
3817
|
"type": "orbit_diagram",
|
|
3775
3818
|
"compact": "animated orbit diagram with satellite nodes",
|
|
3776
3819
|
"surfaces": [
|
|
3820
|
+
"web",
|
|
3777
3821
|
"google-apps-script-web",
|
|
3778
3822
|
"mcp-apps"
|
|
3779
3823
|
]
|
|
@@ -3782,6 +3826,7 @@
|
|
|
3782
3826
|
"type": "noise_card",
|
|
3783
3827
|
"compact": "dark card with film-grain noise texture",
|
|
3784
3828
|
"surfaces": [
|
|
3829
|
+
"web",
|
|
3785
3830
|
"google-apps-script-web",
|
|
3786
3831
|
"mcp-apps"
|
|
3787
3832
|
]
|
|
@@ -3790,6 +3835,7 @@
|
|
|
3790
3835
|
"type": "comparison_morph",
|
|
3791
3836
|
"compact": "draggable before/after comparison slider",
|
|
3792
3837
|
"surfaces": [
|
|
3838
|
+
"web",
|
|
3793
3839
|
"google-apps-script-web",
|
|
3794
3840
|
"mcp-apps"
|
|
3795
3841
|
]
|
|
@@ -3814,6 +3860,7 @@
|
|
|
3814
3860
|
"type": "globe_3d",
|
|
3815
3861
|
"compact": "interactive spinning 3-D globe (wire or earth)",
|
|
3816
3862
|
"surfaces": [
|
|
3863
|
+
"web",
|
|
3817
3864
|
"google-apps-script-web",
|
|
3818
3865
|
"mcp-apps"
|
|
3819
3866
|
]
|
|
@@ -3870,6 +3917,7 @@
|
|
|
3870
3917
|
"type": "surface_unlocked",
|
|
3871
3918
|
"compact": "achievement-style surface unlocked notification",
|
|
3872
3919
|
"surfaces": [
|
|
3920
|
+
"web",
|
|
3873
3921
|
"google-apps-script-web",
|
|
3874
3922
|
"mcp-apps"
|
|
3875
3923
|
]
|
|
@@ -3886,6 +3934,7 @@
|
|
|
3886
3934
|
"type": "url_anatomy",
|
|
3887
3935
|
"compact": "annotated URL anatomy diagram",
|
|
3888
3936
|
"surfaces": [
|
|
3937
|
+
"web",
|
|
3889
3938
|
"google-apps-script-web",
|
|
3890
3939
|
"mcp-apps"
|
|
3891
3940
|
]
|
|
@@ -3907,6 +3956,7 @@
|
|
|
3907
3956
|
"type": "take_away_card",
|
|
3908
3957
|
"compact": "bold screenshot-ready insight card",
|
|
3909
3958
|
"surfaces": [
|
|
3959
|
+
"web",
|
|
3910
3960
|
"google-apps-script-web",
|
|
3911
3961
|
"mcp-apps"
|
|
3912
3962
|
]
|
|
@@ -3915,6 +3965,7 @@
|
|
|
3915
3965
|
"type": "next_step_strip",
|
|
3916
3966
|
"compact": "horizontal numbered next-steps strip",
|
|
3917
3967
|
"surfaces": [
|
|
3968
|
+
"web",
|
|
3918
3969
|
"google-apps-script-web",
|
|
3919
3970
|
"mcp-apps"
|
|
3920
3971
|
]
|
|
@@ -3931,6 +3982,7 @@
|
|
|
3931
3982
|
"type": "atom_anatomy",
|
|
3932
3983
|
"compact": "rendered atom + raw schema side-by-side anatomy view",
|
|
3933
3984
|
"surfaces": [
|
|
3985
|
+
"web",
|
|
3934
3986
|
"google-apps-script-web",
|
|
3935
3987
|
"mcp-apps"
|
|
3936
3988
|
]
|
|
@@ -3939,6 +3991,7 @@
|
|
|
3939
3991
|
"type": "renderer_stats",
|
|
3940
3992
|
"compact": "stat grid for renderer capability metrics",
|
|
3941
3993
|
"surfaces": [
|
|
3994
|
+
"web",
|
|
3942
3995
|
"google-apps-script-web",
|
|
3943
3996
|
"mcp-apps"
|
|
3944
3997
|
]
|
|
@@ -3947,6 +4000,7 @@
|
|
|
3947
4000
|
"type": "prompt_to_schema",
|
|
3948
4001
|
"compact": "three-panel prompt → schema → output flow",
|
|
3949
4002
|
"surfaces": [
|
|
4003
|
+
"web",
|
|
3950
4004
|
"google-apps-script-web",
|
|
3951
4005
|
"mcp-apps"
|
|
3952
4006
|
]
|
|
@@ -3987,6 +4041,7 @@
|
|
|
3987
4041
|
"type": "surface_map",
|
|
3988
4042
|
"compact": "A2UI surface diagram (schema → surfaces)",
|
|
3989
4043
|
"surfaces": [
|
|
4044
|
+
"web",
|
|
3990
4045
|
"google-apps-script-web",
|
|
3991
4046
|
"mcp-apps"
|
|
3992
4047
|
]
|