rl-environments-guide / app /src /content /embeds /framework-cards.html
AdithyaSK's picture
AdithyaSK HF Staff
Update app/src/content/embeds/framework-cards.html (#4)
0cd9877
<div class="fw-cards" style="width:100%;margin:14px 0;"></div>
<style>
.fw-cards {
border: 1px solid var(--border-color);
border-radius: 12px;
background: var(--surface-bg);
overflow: hidden;
color: var(--text-color);
}
.fw-cards__head {
display: flex; align-items: center; gap: 12px;
padding: 8px 12px;
border-bottom: 1px solid var(--border-color);
background: color-mix(in oklab, var(--muted-color) 4%, transparent);
flex-wrap: wrap;
}
.fw-cards__title {
font-size: 10.5px;
font-weight: 800;
letter-spacing: 1px;
text-transform: uppercase;
color: var(--muted-color);
margin-right: auto;
}
.fw-cards__view {
display: inline-flex;
background: var(--surface-bg);
border: 1px solid var(--border-color);
border-radius: 6px;
padding: 2px;
gap: 2px;
}
.fw-cards__view button {
border: 0;
background: transparent;
color: var(--muted-color);
font-size: 10.5px;
font-weight: 700;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
letter-spacing: 0.4px;
text-transform: uppercase;
}
.fw-cards__view button.active {
color: var(--text-color);
background: color-mix(in oklab, var(--text-color) 8%, transparent);
}
.fw-cards__body > div { display: none; }
.fw-cards__body > div.active { display: block; }
/* ── Cards view ── */
.fw-cards__grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
padding: 12px;
background: color-mix(in oklab, var(--muted-color) 3%, transparent);
}
@media (max-width: 880px) { .fw-cards__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 580px) { .fw-cards__grid { grid-template-columns: minmax(0, 1fr); } }
.fw-card {
position: relative;
border: 1px solid var(--border-color);
border-radius: 10px;
background: var(--surface-bg);
padding: 14px 14px 12px 14px;
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 8px;
overflow: hidden;
min-width: 0;
}
.fw-card::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0;
height: 2px;
background: var(--fw-accent);
}
.fw-card__row {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 10px;
min-width: 0;
}
.fw-card__title-block { flex: 1 1 auto; min-width: 0; }
.fw-card__name {
font-size: 14.5px;
font-weight: 700;
color: var(--text-color);
line-height: 1.2;
}
.fw-card__creator {
font-size: 11px;
color: var(--muted-color);
margin-top: 2px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.fw-card__transport {
flex-shrink: 0;
display: inline-flex;
align-items: center;
gap: 3px;
padding: 2px 7px;
border-radius: 999px;
border: 1px solid color-mix(in oklab, var(--fw-accent) 30%, var(--border-color));
color: color-mix(in oklab, var(--fw-accent) 90%, var(--text-color));
background: color-mix(in oklab, var(--fw-accent) 10%, transparent);
font-size: 9px;
font-weight: 700;
letter-spacing: 0.3px;
text-transform: uppercase;
white-space: nowrap;
line-height: 1;
}
.fw-card__transport svg { width: 9px; height: 9px; flex-shrink: 0; }
.fw-card__tagline {
font-size: 12px;
line-height: 1.5;
color: var(--muted-color);
}
.fw-card__meta {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
margin-top: auto;
}
.fw-card__pkg {
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 11px;
background: color-mix(in oklab, var(--muted-color) 8%, transparent);
border: 1px solid var(--border-color);
border-radius: 5px;
padding: 2px 7px;
color: var(--text-color);
}
.fw-card__pyver {
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 10.5px;
color: var(--muted-color);
}
.fw-card__action {
display: inline-flex;
align-items: center;
gap: 5px;
color: var(--muted-color);
font-size: 11.5px;
font-weight: 600;
text-decoration: none;
transition: color .12s ease;
margin-left: auto;
}
.fw-card__action:hover { color: var(--fw-accent); }
.fw-card__action svg { width: 12px; height: 12px; flex-shrink: 0; }
/* ── Table view ── */
.fw-cards__table-wrap { overflow-x: auto; }
.fw-cards__table-wrap table {
width: 100%;
border-collapse: collapse;
font-size: 12.5px;
min-width: 640px;
}
.fw-cards__table-wrap thead th {
text-align: left;
font-size: 10.5px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.6px;
color: var(--muted-color);
padding: 10px 12px;
border-bottom: 1px solid var(--border-color);
background: color-mix(in oklab, var(--muted-color) 3%, transparent);
white-space: nowrap;
}
.fw-cards__table-wrap tbody td {
padding: 10px 12px;
border-bottom: 1px solid color-mix(in oklab, var(--border-color) 60%, transparent);
vertical-align: middle;
color: var(--text-color);
font-size: 12px;
line-height: 1.5;
}
.fw-cards__table-wrap tbody tr:last-child td { border-bottom: 0; }
.fw-cards__table-wrap tbody tr:hover td {
background: color-mix(in oklab, var(--muted-color) 3%, transparent);
}
.fw-cards__table-wrap td.idx {
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
color: var(--muted-color);
font-size: 11px;
width: 28px;
}
.fw-cards__table-wrap td.fw-name {
font-weight: 700;
white-space: nowrap;
}
.fw-cards__table-wrap td.fw-name a {
color: var(--text-color);
text-decoration: none;
border-bottom: 2px solid var(--fw-accent);
padding-bottom: 1px;
}
.fw-cards__table-wrap td.fw-name a:hover { color: var(--fw-accent); }
.fw-cards__table-wrap td.fw-name .swatch {
width: 8px; height: 8px; border-radius: 50%;
background: var(--fw-accent);
display: inline-block;
margin-right: 7px;
vertical-align: middle;
}
.fw-cards__table-wrap code {
background: color-mix(in oklab, var(--muted-color) 10%, transparent);
border-radius: 3px;
padding: 0 5px;
font-size: 11px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.fwt-pill {
display: inline-flex; align-items: center; gap: 4px;
padding: 1px 8px;
border-radius: 999px;
font-size: 10.5px;
font-weight: 700;
letter-spacing: 0.4px;
}
.fwt-pill.http { background: color-mix(in oklab, #3b82f6 12%, transparent); color: color-mix(in oklab, #3b82f6 80%, var(--text-color)); border: 1px solid color-mix(in oklab, #3b82f6 30%, transparent); }
.fwt-pill.inproc { background: color-mix(in oklab, #ec4899 10%, transparent); color: color-mix(in oklab, #ec4899 80%, var(--text-color)); border: 1px solid color-mix(in oklab, #ec4899 28%, transparent); }
</style>
<script>
(() => {
const bootstrap = () => {
const scriptEl = document.currentScript;
let container = scriptEl ? scriptEl.previousElementSibling : null;
if (!(container && container.classList && container.classList.contains('fw-cards'))) {
const cands = Array.from(document.querySelectorAll('.fw-cards'))
.filter(el => !(el.dataset && el.dataset.mounted === 'true'));
container = cands[cands.length - 1] || null;
}
if (!container || (container.dataset && container.dataset.mounted === 'true')) return;
container.dataset.mounted = 'true';
const FRAMEWORKS = [
{ name: 'OpenEnv', creator: 'Meta PyTorch', accent: '#3b82f6', transport: 'http', typeLabel: 'HTTP server (MCP)', tagline: 'MCP-based protocol with composable Rubric rewards.', package: 'openenv-core', pkgSrc: 'PyPI', python: '≥3.11', repo: 'https://github.com/meta-pytorch/OpenEnv' },
{ name: 'ORS', creator: 'General Reasoning', accent: '#a855f7', transport: 'http', typeLabel: 'HTTP server (REST+SSE)', tagline: 'Per-tool-call rewards via ToolOutput, large catalog.', package: 'ors-sdk', pkgSrc: 'PyPI', python: '≥3.10', repo: 'https://openrewardstandard.io/' },
{ name: 'NeMo Gym', creator: 'NVIDIA', accent: '#22c55e', transport: 'http', typeLabel: 'HTTP server (REST)', tagline: 'FastAPI tools + post-episode /verify endpoint.', package: 'nemo_gym', pkgSrc: 'Git', python: '≥3.12', repo: 'https://github.com/NVIDIA-NeMo/Gym' },
{ name: 'Verifiers', creator: 'PrimeIntellect', accent: '#ec4899', transport: 'inproc', typeLabel: 'In-process Python', tagline: 'Bundled dataset, tools, Rubric, and trainer.', package: 'verifiers', pkgSrc: 'PyPI', python: '≥3.11', repo: 'https://github.com/PrimeIntellect-ai/verifiers' },
{ name: 'SkyRL Gym', creator: 'NovaSky-AI · Berkeley', accent: '#f59e0b', transport: 'inproc', typeLabel: 'In-process (Gym)', tagline: 'Lightweight Gym-style API with ToolGroups.', package: 'skyrl-gym', pkgSrc: 'PyPI', python: '≥3.10', repo: 'https://github.com/NovaSky-AI/SkyRL' },
{ name: 'GEM', creator: 'Axon-RL', accent: '#14b8a6', transport: 'inproc', typeLabel: 'In-process (Gymnasium)', tagline: 'Strict Gymnasium 5-tuple, 24+ built-in envs.', package: 'gem-llm', pkgSrc: 'PyPI', python: '≥3.10', repo: 'https://github.com/axon-rl/gem' },
];
const ICON_HTTP = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.5 19a4.5 4.5 0 1 0-1.4-8.78A6 6 0 0 0 4 12.5 4.5 4.5 0 0 0 6.5 19h11Z"/></svg>`;
const ICON_INPROC = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="6" width="12" height="12" rx="2"/><path d="M9 1v3M15 1v3M9 20v3M15 20v3M1 9h3M1 15h3M20 9h3M20 15h3"/></svg>`;
const ICON_REPO = `<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 .3a12 12 0 0 0-3.8 23.4c.6.1.8-.3.8-.6v-2c-3.3.7-4-1.4-4-1.4-.6-1.4-1.4-1.8-1.4-1.8-1.1-.8.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1.1 1.8 2.8 1.3 3.5 1 .1-.8.4-1.3.8-1.6-2.7-.3-5.5-1.3-5.5-6 0-1.3.5-2.4 1.2-3.2-.1-.3-.5-1.5.1-3.2 0 0 1-.3 3.3 1.2a11 11 0 0 1 6 0c2.3-1.5 3.3-1.2 3.3-1.2.6 1.7.2 2.9.1 3.2.8.8 1.2 1.9 1.2 3.2 0 4.7-2.8 5.7-5.5 6 .4.4.8 1.1.8 2.2v3.3c0 .3.2.7.8.6A12 12 0 0 0 12 .3Z"/></svg>`;
const cardsHtml = FRAMEWORKS.map(fw => {
const transportIcon = fw.transport === 'http' ? ICON_HTTP : ICON_INPROC;
const transportLabel = fw.transport === 'http' ? 'HTTP' : 'In-proc';
return `
<div class="fw-card" style="--fw-accent:${fw.accent};">
<div class="fw-card__row">
<div class="fw-card__title-block">
<div class="fw-card__name">${fw.name}</div>
<div class="fw-card__creator">${fw.creator}</div>
</div>
<span class="fw-card__transport">${transportIcon}<span>${transportLabel}</span></span>
</div>
<div class="fw-card__tagline">${fw.tagline}</div>
<div class="fw-card__meta">
<span class="fw-card__pkg">${fw.package}</span>
<span class="fw-card__pyver">python ${fw.python}</span>
<a class="fw-card__action" href="${fw.repo}" target="_blank" rel="noopener">${ICON_REPO}<span>Repo</span></a>
</div>
</div>
`;
}).join('');
const tableRows = FRAMEWORKS.map((fw, i) => `
<tr style="--fw-accent:${fw.accent};">
<td class="idx">${i + 1}</td>
<td class="fw-name"><span class="swatch"></span><a href="${fw.repo}" target="_blank" rel="noopener">${fw.name}</a></td>
<td>${fw.creator}</td>
<td><span class="fwt-pill ${fw.transport}">${fw.typeLabel}</span></td>
<td><code>${fw.package}</code> <span style="color:var(--muted-color); font-size:10.5px;">(${fw.pkgSrc})</span></td>
</tr>
`).join('');
container.innerHTML = `
<div class="fw-cards__head">
<span class="fw-cards__title">Frameworks we implemented and compared</span>
<div class="fw-cards__view" role="tablist">
<button type="button" data-view="table" class="active">Table</button>
<button type="button" data-view="cards">Cards</button>
</div>
</div>
<div class="fw-cards__body">
<div data-pane="table" class="active">
<div class="fw-cards__table-wrap">
<table>
<thead>
<tr>
<th>#</th>
<th>Framework</th>
<th>Creator</th>
<th>Type</th>
<th>Package</th>
</tr>
</thead>
<tbody>${tableRows}</tbody>
</table>
</div>
</div>
<div data-pane="cards">
<div class="fw-cards__grid">${cardsHtml}</div>
</div>
</div>
`;
const buttons = container.querySelectorAll('.fw-cards__view button');
const panes = container.querySelectorAll('.fw-cards__body > div');
buttons.forEach(b => b.addEventListener('click', () => {
const v = b.getAttribute('data-view');
buttons.forEach(x => x.classList.toggle('active', x === b));
panes.forEach(p => p.classList.toggle('active', p.getAttribute('data-pane') === v));
}));
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', bootstrap, { once: true });
} else {
bootstrap();
}
})();
</script>