Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions projects/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ NVIDIA Design System and UI Agent Harness for AI/ML Factories, Robotics, and Aut

## Getting Started

```shell
# local .npmrc file
registry=https://registry.npmjs.org

# https://registry.npmjs.org
npm login
Install the packages from the public npm registry:

```shell
npm install @nvidia-elements/themes @nvidia-elements/styles @nvidia-elements/core
```

## Framework integration

Use React, Vue, and Angular as integration targets for these Web Components. See the [integration guides](https://NVIDIA.github.io/elements/docs/integrations/) for framework setup.

Elements ships as many small packages. This allows you to choose what tools your application needs and omit anything unnecessary, improving application performance.

## Usage
Expand Down
5 changes: 4 additions & 1 deletion projects/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
"design-system",
"ui-components",
"accessibility",
"lit"
"lit",
"react",
"vue",
"angular"
],
"homepage": "https://NVIDIA.github.io/elements/",
"repository": {
Expand Down
95 changes: 95 additions & 0 deletions projects/site/src/_11ty/context/mcp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# MCP

The NVIDIA Elements MCP server gives AI assistants Model Context Protocol access to component APIs, examples, design tokens, icons, and project setup.

## Quick setup

Install the Elements CLI, then run project setup. The command detects the package manager, configures the MCP server for Cursor, Claude Code, and Codex, and adds the Elements core dependencies.

```shell
nve project.setup
```

## Cursor

Save this configuration as `.cursor/mcp.json`, then enable the Elements server in Cursor settings.

```json
{
"mcpServers": {
"elements": {
"description": "NVIDIA Elements UI Design System (nve-*), custom element schemas, APIs and examples",
"command": "nve",
"args": ["mcp"]
}
}
}
```

## Claude Code

Save this configuration as `.mcp.json`, then restart Claude Code.

```json
{
"mcpServers": {
"elements": {
"description": "NVIDIA Elements UI Design System (nve-*), custom element schemas, APIs and examples",
"command": "nve",
"args": ["mcp"]
}
}
}
```

## Codex

Save this configuration as `.codex/config.toml`, then restart Codex.

```toml
[mcp_servers.elements]
description = "NVIDIA Elements UI Design System (nve-*), custom element schemas, APIs and examples"
command = "nve"
args = ["mcp"]
```

## Prompt examples

- `/artifact` creates a standalone Elements UI artifact. Example prompt: `/artifact Create an example login form`.
- `/doctor` checks Elements setup and MCP configuration.
- `/create-project` creates an Elements starter project. Example prompt: `/create-project Create an Angular todo app`.
- `/migrate` updates a project from deprecated Elements APIs. Example prompt: `/migrate Migrate this project from deprecated Elements APIs`.

## Tool examples

`api_validate` checks HTML or JSON. This call checks a button template:

```json
{ "template": "<nve-button>Save</nve-button>", "format": "json" }
```

`examples_get` returns a stored example template. `examples_render` renders custom Elements HTML in the MCP Apps preview.

| Tool | Description |
| ------------------------- | -------------------------------------------------------- |
| `api_list` | List Elements APIs and components. |
| `api_get` | Read documentation for known components or attributes. |
| `api_validate` | Check HTML and JSON with Elements lint rules. |
| `api_imports_get` | Return ESM imports for an HTML template. |
| `api_tokens_list` | List semantic CSS custom properties and design tokens. |
| `api_icons_list` | List icon names for `nve-icon` and `nve-icon-button`. |
| `examples_list` | List patterns and examples. |
| `examples_get` | Return a known example or pattern template. |
| `examples_render` | Render a custom Elements HTML template in the preview. |
| `playground_validate` | Validate HTML for a playground example. |
| `playground_create` | Create a shareable playground URL from an HTML template. |
| `packages_list` | List the latest published Elements package versions. |
| `packages_get` | Read details for one Elements package. |
| `packages_changelogs_get` | Read changelog details for a package. |
| `project_create` | Create a starter project. |
| `project_validate` | Check project configuration and dependencies. |
| `project_setup` | Set up or update a project to use Elements. |

## MCP Apps

Hosts that support MCP Apps can render the example preview, icon list, and token explorer inline. The example preview uses `ui://elements/example-preview` for `examples_get` and `examples_render`.
95 changes: 85 additions & 10 deletions projects/site/src/_11ty/layouts/metadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,8 @@ function getDescriptionContexts(data) {
];
}

function expandShortDescription(data, description) {
function expandShortDescription(data, description, { preserve = false } = {}) {
if (preserve && description.length >= MIN_DESCRIPTION_LENGTH) return description;
if (description.length >= MIN_DESCRIPTION_LENGTH) return clampDescription(description);

const contexts = getDescriptionContexts(data);
Expand All @@ -349,16 +350,88 @@ function expandShortDescription(data, description) {
return clampDescription(expandedDescription);
}

const API_DESCRIPTION_PHRASES = [
'Documents properties, events, slots, and CSS.',
'Includes commands and styling hooks.',
'Supports production interface workflows.',
'For Web Components.',
'For app teams.',
'For apps.'
];

const EXAMPLES_DESCRIPTION_PHRASES = [
'Shows markup patterns, states, and usage.',
'Includes runnable component examples.',
'Covers actions and layout.',
'For Web Components.',
'For app teams.',
'For apps.'
];

function lastIndexBefore(description, max, isMatch, includeChar) {
const limit = Math.min(description.length, max);
let index = -1;

for (let i = 0; i < limit; i++) {
if (!isMatch(description[i], description[i + 1])) continue;
index = includeChar ? i + 1 : i;
}

return index;
}

function clampDescription(description) {
if (description.length <= MAX_DESCRIPTION_LENGTH) return description;

const sentenceEnd = lastIndexBefore(
description,
MAX_DESCRIPTION_LENGTH,
(char, next) => (char === '.' || char === '!' || char === '?') && (next === undefined || /\s/u.test(next)),
true
);
if (sentenceEnd >= MIN_DESCRIPTION_LENGTH) return description.slice(0, sentenceEnd).trimEnd();

const clauseEnd = lastIndexBefore(
description,
MAX_DESCRIPTION_LENGTH,
char => char === ',' || char === ';' || char === ':' || char === '—',
false
);
if (clauseEnd >= MIN_DESCRIPTION_LENGTH) {
const clause = description
.slice(0, clauseEnd)
.replace(/[,:;—]+$/u, '')
.trimEnd();
if (clause.length >= MIN_DESCRIPTION_LENGTH) return clause;
}

const trimmed = description.slice(0, MAX_DESCRIPTION_LENGTH).trimEnd();
const lastSpace = trimmed.lastIndexOf(' ');
const sentence = (lastSpace === -1 ? trimmed : trimmed.slice(0, lastSpace))
.replace(/[,:;—-]+$/u, '')
.replace(/[.?!]$/u, '');
return (lastSpace === -1 ? trimmed : trimmed.slice(0, lastSpace)).replace(/[,:;—-]+$/u, '').trimEnd();
}

function fitDescription(lead, phrases) {
let text = lead;

for (const phrase of phrases) {
if (text.length >= MIN_DESCRIPTION_LENGTH) return text;
const next = `${text} ${phrase}`;
if (next.length <= MAX_DESCRIPTION_LENGTH) text = next;
}

return text;
}

function componentTabDescription(kind, tag, componentDescription) {
const purpose = kind === 'api' ? `API reference for <${tag}>.` : `Interactive examples for <${tag}>.`;
const qualified = `${componentDescription} — ${purpose}`;
if (qualified.length <= MAX_DESCRIPTION_LENGTH) return qualified;

const phrases = kind === 'api' ? API_DESCRIPTION_PHRASES : EXAMPLES_DESCRIPTION_PHRASES;
const fitted = fitDescription(purpose, phrases);
if (fitted.length <= MAX_DESCRIPTION_LENGTH) return fitted;

return sentence.length < MAX_DESCRIPTION_LENGTH ? `${sentence}.` : sentence;
return clampDescription(fitted);
}

function hasGeneratedPage(data, generatedUrls, url) {
Expand All @@ -375,12 +448,14 @@ export function resolvePageMeta(data) {
const componentDescription = element?.manifest?.description?.trim();

let description;
if (data.description) {
description = data.description;
let authored = false;
if (typeof data.description === 'string' && data.description.trim()) {
description = data.description.trim();
authored = true;
} else if (data.isApiTab && componentDescription) {
description = `${componentDescription} — API reference for <${tag}>.`;
description = componentTabDescription('api', tag, componentDescription);
} else if (data.isExamplesTab && componentDescription) {
description = `${componentDescription} — Interactive examples for <${tag}>.`;
description = componentTabDescription('examples', tag, componentDescription);
} else if (data.changelog?.description) {
description = `Changelog for ${data.changelog.title}: ${data.changelog.description}`;
} else if (componentDescription) {
Expand All @@ -392,7 +467,7 @@ export function resolvePageMeta(data) {
description = `Documentation for ${rawTitle} in NVIDIA Elements, the framework-agnostic design system for AI/ML factories.`;
}

description = expandShortDescription(data, description);
description = expandShortDescription(data, description, { preserve: authored });

const canonicalUrl = getSiteUrl(url);
const ogImage = SOCIAL_IMAGE_URL;
Expand Down
Loading
Loading