static_transformer / index.html
ereeyees's picture
Update index.html
4678c63 verified
Raw
History Blame Contribute Delete
28 kB
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Affordances computationnelles — atlas UI</title>
<style>
:root {
--bg: #f7f4ef;
--surface: #ffffff;
--surface-2: #f0ece5;
--ink: #1f1f1f;
--muted: #62605b;
--line: #d8d0c4;
--accent: #315c72;
--accent-2: #8b4b35;
--ok: #2f6c4f;
--warn: #8a5a00;
--shadow: 0 16px 45px rgba(31, 31, 31, 0.08);
--radius: 22px;
--mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
--sans: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
--serif: Georgia, "Times New Roman", serif;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
color: var(--ink);
background:
radial-gradient(circle at top left, rgba(49, 92, 114, 0.14), transparent 32rem),
radial-gradient(circle at 90% 10%, rgba(139, 75, 53, 0.12), transparent 24rem),
var(--bg);
font-family: var(--sans);
line-height: 1.5;
}
button, input, select, textarea { font: inherit; }
a { color: inherit; }
.wrap {
width: min(1180px, calc(100vw - 32px));
margin: 0 auto;
}
header {
padding: 48px 0 28px;
}
.eyebrow {
display: inline-flex;
gap: 8px;
align-items: center;
padding: 6px 10px;
border: 1px solid var(--line);
border-radius: 999px;
background: rgba(255, 255, 255, 0.72);
color: var(--muted);
font-size: 0.86rem;
}
.dot {
width: 8px;
height: 8px;
border-radius: 999px;
background: var(--ok);
}
h1 {
max-width: 900px;
margin: 18px 0 12px;
font-family: var(--serif);
font-size: clamp(2.25rem, 6vw, 5rem);
line-height: 0.96;
letter-spacing: -0.055em;
}
.lead {
max-width: 760px;
margin: 0;
color: var(--muted);
font-size: clamp(1.02rem, 1.8vw, 1.22rem);
}
.toolbar {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 24px;
}
.pill, .chip {
display: inline-flex;
gap: 8px;
align-items: center;
min-height: 32px;
padding: 7px 11px;
border: 1px solid var(--line);
border-radius: 999px;
background: rgba(255, 255, 255, 0.72);
color: var(--muted);
font-size: 0.88rem;
white-space: nowrap;
}
main { padding: 8px 0 54px; }
.figure-board {
display: grid;
grid-template-columns: 1.15fr 0.85fr;
gap: 18px;
margin: 20px 0 24px;
}
.panel, .card {
background: rgba(255, 255, 255, 0.82);
border: 1px solid rgba(216, 208, 196, 0.92);
border-radius: var(--radius);
box-shadow: var(--shadow);
backdrop-filter: blur(12px);
}
.panel { padding: 18px; }
.panel h2, .card h3 {
margin: 0;
letter-spacing: -0.02em;
}
.panel h2 {
font-size: 1.15rem;
}
.panel p, .card p {
margin: 8px 0 0;
color: var(--muted);
}
.layers {
display: grid;
gap: 12px;
margin-top: 16px;
}
.layer {
display: grid;
grid-template-columns: 150px 1fr;
gap: 14px;
align-items: start;
padding: 14px;
border: 1px solid var(--line);
border-radius: 18px;
background: var(--surface);
}
.layer strong { font-size: 0.95rem; }
.layer span { color: var(--muted); }
.timeline {
display: grid;
gap: 10px;
margin-top: 16px;
}
.time-item {
display: grid;
grid-template-columns: 64px 1fr;
gap: 12px;
padding: 11px 0;
border-bottom: 1px solid var(--line);
}
.time-item:last-child { border-bottom: 0; }
.time-item time { color: var(--accent); font-weight: 700; }
.time-item b { display: block; }
.time-item span { color: var(--muted); font-size: 0.92rem; }
.grid {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 18px;
margin-top: 18px;
}
.card {
grid-column: span 6;
overflow: hidden;
}
.card.wide { grid-column: span 12; }
.card.small { grid-column: span 4; }
.card-head {
display: flex;
justify-content: space-between;
gap: 14px;
padding: 18px 18px 0;
}
.tag {
align-self: start;
padding: 5px 9px;
border-radius: 999px;
background: var(--surface-2);
color: var(--muted);
font-size: 0.78rem;
white-space: nowrap;
}
.ui {
margin: 16px 18px 18px;
padding: 14px;
border: 1px solid var(--line);
border-radius: 18px;
background: linear-gradient(180deg, rgba(255,255,255,0.72), rgba(240,236,229,0.6));
}
label {
display: block;
margin: 0 0 6px;
color: var(--muted);
font-size: 0.84rem;
font-weight: 650;
}
textarea, input[type="text"], select {
width: 100%;
min-height: 42px;
border: 1px solid var(--line);
border-radius: 14px;
padding: 10px 12px;
background: #fff;
color: var(--ink);
outline: none;
}
textarea { min-height: 92px; resize: vertical; }
input[type="range"] { width: 100%; }
.row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
margin-top: 12px;
}
.actions {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 12px;
}
.btn {
border: 0;
border-radius: 999px;
padding: 10px 14px;
background: var(--ink);
color: white;
cursor: pointer;
transition: transform 160ms ease, opacity 160ms ease;
}
.btn:hover { transform: translateY(-1px); }
.btn:disabled { cursor: wait; opacity: 0.62; transform: none; }
.btn.secondary {
border: 1px solid var(--line);
background: #fff;
color: var(--ink);
}
.btn.ghost {
background: transparent;
color: var(--accent);
padding-left: 0;
padding-right: 0;
}
.output {
min-height: 58px;
margin-top: 12px;
padding: 12px;
border: 1px dashed rgba(49, 92, 114, 0.38);
border-radius: 14px;
background: rgba(49, 92, 114, 0.06);
color: #27343a;
}
.output[aria-busy="true"]::after {
content: "";
display: inline-block;
width: 10px;
height: 10px;
margin-left: 8px;
border-radius: 50%;
border: 2px solid currentColor;
border-top-color: transparent;
animation: spin 900ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.meter {
height: 8px;
border-radius: 999px;
background: var(--surface-2);
overflow: hidden;
margin-top: 8px;
}
.meter > i {
display: block;
height: 100%;
width: var(--value, 48%);
background: var(--accent);
}
.gallery {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
margin-top: 12px;
}
.thumb {
aspect-ratio: 1;
border: 1px solid var(--line);
border-radius: 14px;
background:
radial-gradient(circle at var(--x, 50%) var(--y, 50%), rgba(49,92,114,0.66), transparent 32%),
linear-gradient(var(--angle, 135deg), rgba(139,75,53,0.28), rgba(255,255,255,0.85));
position: relative;
overflow: hidden;
}
.thumb::after {
content: attr(data-seed);
position: absolute;
right: 8px;
bottom: 6px;
color: rgba(31,31,31,0.54);
font: 700 0.72rem var(--mono);
}
pre {
margin: 0;
padding: 12px;
overflow: auto;
border-radius: 14px;
background: #1f1f1f;
color: #f5f1e9;
font-family: var(--mono);
font-size: 0.82rem;
}
code { font-family: var(--mono); }
.checks {
display: grid;
gap: 8px;
margin-top: 10px;
}
.check {
display: flex;
align-items: center;
gap: 8px;
color: var(--muted);
}
.latent {
position: relative;
height: 250px;
border: 1px solid var(--line);
border-radius: 18px;
overflow: hidden;
background:
linear-gradient(90deg, rgba(49,92,114,0.12), transparent),
linear-gradient(0deg, rgba(139,75,53,0.16), transparent),
repeating-linear-gradient(0deg, rgba(31,31,31,0.04), rgba(31,31,31,0.04) 1px, transparent 1px, transparent 24px),
repeating-linear-gradient(90deg, rgba(31,31,31,0.04), rgba(31,31,31,0.04) 1px, transparent 1px, transparent 24px),
#fff;
}
.latent-dot {
position: absolute;
left: var(--lx, 50%);
top: var(--ly, 50%);
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--accent-2);
box-shadow: 0 0 0 10px rgba(139, 75, 53, 0.14);
transform: translate(-50%, -50%);
}
.latent-label {
position: absolute;
left: 14px;
bottom: 12px;
max-width: calc(100% - 28px);
padding: 8px 10px;
border-radius: 12px;
background: rgba(255,255,255,0.82);
color: var(--muted);
font-size: 0.86rem;
}
.flow {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 10px;
margin-top: 12px;
}
.step {
min-height: 78px;
padding: 10px;
border: 1px solid var(--line);
border-radius: 14px;
background: #fff;
}
.step b { display: block; font-size: 0.88rem; }
.step span { color: var(--muted); font-size: 0.82rem; }
footer {
padding: 20px 0 46px;
color: var(--muted);
font-size: 0.92rem;
}
@media (max-width: 880px) {
.figure-board { grid-template-columns: 1fr; }
.card, .card.small { grid-column: span 12; }
.row, .layer { grid-template-columns: 1fr; }
.flow { grid-template-columns: 1fr; }
}
@media print {
body { background: white; }
header, footer { padding: 10px 0; }
.btn, .toolbar { display: none; }
.panel, .card { box-shadow: none; break-inside: avoid; }
}
</style>
</head>
<body>
<header class="wrap">
<div class="eyebrow"><span class="dot" aria-hidden="true"></span> Hugging Face Space · static HTML · Transformers.js</div>
<h1>Atlas d’interfaces web génératives</h1>
<p class="lead">Cette page propose une figure exploratoire : elle regroupe des composants visibles de l’interface et les relie à des opérations plus profondes — modèle, paramètres, API, bibliothèque et environnement de travail.</p>
<nav class="toolbar" aria-label="Repères">
<a class="pill" href="#prompt">Prompt</a>
<a class="pill" href="#parametres">Paramètres</a>
<a class="pill" href="#variations">Variations</a>
<a class="pill" href="#assistant">Assistant</a>
<a class="pill" href="#api">API</a>
<a class="pill" href="#local">Modèle local</a>
<a class="pill" href="#latent">Espace latent</a>
<a class="pill" href="#workflow">Workflow</a>
</nav>
</header>
<main class="wrap">
<section class="figure-board" aria-label="Synthèse des couches">
<div class="panel">
<h2>Couches d’une affordance computationnelle</h2>
<p>Une action visible dans le navigateur donne accès à une chaîne de traitement qui reste partiellement masquée.</p>
<div class="layers">
<div class="layer">
<strong>Surface visible</strong>
<span>Champ de prompt, bouton de génération, curseur, sortie, historique, galerie.</span>
</div>
<div class="layer">
<strong>Procédure</strong>
<span>Prétraitement, inférence, paramètres, filtrage, post-traitement, export.</span>
</div>
<div class="layer">
<strong>Infrastructure</strong>
<span>Modèle, bibliothèque IA, pipeline, navigateur, GPU/CPU, API, espace de déploiement.</span>
</div>
</div>
</div>
<aside class="panel">
<h2>Repères d’évolution</h2>
<p>Quelques composants du web génératif se stabilisent progressivement dans les interfaces.</p>
<div class="timeline">
<div class="time-item"><time>2020</time><span><b>API de modèles</b> Intégrer des traitements génératifs dans une application web.</span></div>
<div class="time-item"><time>2021</time><span><b>Spaces / démos</b> Publier et tester un modèle depuis un navigateur.</span></div>
<div class="time-item"><time>2022</time><span><b>Diffusion</b> Généraliser prompt, paramètres et galerie de sorties visuelles.</span></div>
<div class="time-item"><time>2023</time><span><b>Assistants</b> Configurer des instructions, connaissances et actions.</span></div>
<div class="time-item"><time>2024+</time><span><b>WebGPU / local</b> Exécuter certains modèles directement dans le navigateur.</span></div>
</div>
</aside>
</section>
<section class="grid" aria-label="Options d’interfaces UI">
<article class="card" id="prompt">
<div class="card-head">
<div>
<h3>1. Prompt minimal</h3>
<p>Le champ de consigne devient le composant d’entrée dominant.</p>
</div>
<span class="tag">usage</span>
</div>
<div class="ui">
<label for="promptText">Consigne</label>
<textarea id="promptText">Décrire en trois phrases une affordance computationnelle.</textarea>
<div class="actions">
<button class="btn" data-action="mock-generate">Générer</button>
<button class="btn secondary" data-action="clear-output" data-target="promptOut">Effacer</button>
</div>
<div id="promptOut" class="output" aria-live="polite">Résultat simulé : le système attend une consigne, puis produit une forme médiatique.</div>
</div>
</article>
<article class="card" id="parametres">
<div class="card-head">
<div>
<h3>2. Paramétrage</h3>
<p>La génération devient réglable par modèle, température et longueur.</p>
</div>
<span class="tag">configuration</span>
</div>
<div class="ui">
<div class="row">
<div>
<label for="modelSelect">Modèle</label>
<select id="modelSelect">
<option>modèle léger local</option>
<option>modèle généraliste API</option>
<option>modèle spécialisé image</option>
</select>
</div>
<div>
<label for="formatSelect">Sortie</label>
<select id="formatSelect">
<option>texte court</option>
<option>liste structurée</option>
<option>JSON</option>
</select>
</div>
</div>
<div class="row">
<div>
<label for="temperature">Température : <span id="temperatureValue">0.7</span></label>
<input id="temperature" type="range" min="0" max="1" step="0.1" value="0.7" />
</div>
<div>
<label for="tokens">Longueur : <span id="tokensValue">128</span> tokens</label>
<input id="tokens" type="range" min="32" max="512" step="32" value="128" />
</div>
</div>
<div class="output" id="paramOut">Paramètres actifs : modèle léger local · texte court · température 0.7 · 128 tokens.</div>
</div>
</article>
<article class="card" id="variations">
<div class="card-head">
<div>
<h3>3. Variations visuelles</h3>
<p>Une galerie rend perceptibles les essais, séries et variations.</p>
</div>
<span class="tag">image</span>
</div>
<div class="ui">
<label for="imagePrompt">Prompt image</label>
<input id="imagePrompt" type="text" value="interface web générative, formes latentes, diagramme" />
<div class="row">
<div>
<label for="guidance">Guidance : <span id="guidanceValue">7</span></label>
<input id="guidance" type="range" min="1" max="12" step="1" value="7" />
</div>
<div>
<label for="steps">Étapes : <span id="stepsValue">30</span></label>
<input id="steps" type="range" min="10" max="50" step="5" value="30" />
</div>
</div>
<div class="actions"><button class="btn" data-action="make-gallery">Créer 4 variations</button></div>
<div class="gallery" id="gallery" aria-label="Galerie de variations">
<div class="thumb" data-seed="A1"></div>
<div class="thumb" data-seed="B2"></div>
<div class="thumb" data-seed="C3"></div>
<div class="thumb" data-seed="D4"></div>
</div>
</div>
</article>
<article class="card" id="assistant">
<div class="card-head">
<div>
<h3>4. Assistant configurable</h3>
<p>Les instructions et les ressources transforment un modèle en outil situé.</p>
</div>
<span class="tag">assistant</span>
</div>
<div class="ui">
<label for="systemPrompt">Instructions</label>
<textarea id="systemPrompt">Tu aides à analyser des interfaces web génératives avec un vocabulaire de SIC, design et HCI.</textarea>
<div class="checks" aria-label="Outils activés">
<label class="check"><input type="checkbox" checked /> Corpus de textes</label>
<label class="check"><input type="checkbox" checked /> Génération de tableaux</label>
<label class="check"><input type="checkbox" /> Appel à une API externe</label>
</div>
<div class="output">Assistant : instructions + connaissances + outils. L’affordance devient une configuration réutilisable.</div>
</div>
</article>
<article class="card" id="api">
<div class="card-head">
<div>
<h3>5. API et documentation</h3>
<p>L’interface lisible par l’humain se double d’une interface programmable.</p>
</div>
<span class="tag">développement</span>
</div>
<div class="ui">
<pre id="apiCode"><code>const output = await pipe("Classer ces notes de lecture", {
model: "modèle-compatible-web",
temperature: 0.4,
max_new_tokens: 128
});</code></pre>
<div class="actions">
<button class="btn secondary" data-action="copy-code">Copier le fragment</button>
</div>
<div id="copyOut" class="output">Une API transforme une affordance en composant réutilisable par un autre outil.</div>
</div>
</article>
<article class="card" id="local">
<div class="card-head">
<div>
<h3>6. Modèle local dans le navigateur</h3>
<p>Cette carte utilise Transformers.js pour charger un petit pipeline côté client.</p>
</div>
<span class="tag">transformers.js</span>
</div>
<div class="ui">
<label for="sentimentText">Texte à analyser</label>
<textarea id="sentimentText">I find this browser-based interface useful and surprisingly clear.</textarea>
<div class="actions">
<button class="btn" id="runSentiment">Charger le modèle et analyser</button>
<button class="btn secondary" id="resetSentiment">Réinitialiser</button>
</div>
<div id="sentimentOut" class="output" aria-live="polite">Le modèle sera téléchargé au premier usage. Le calcul s’exécute ensuite dans le navigateur.</div>
</div>
</article>
<article class="card" id="latent">
<div class="card-head">
<div>
<h3>7. Espace latent</h3>
<p>Les curseurs figurent l’exploration d’un espace de possibilités.</p>
</div>
<span class="tag">imaginaire</span>
</div>
<div class="ui">
<div class="latent" id="latentSpace">
<div class="latent-dot" id="latentDot"></div>
<div class="latent-label" id="latentLabel">Position : proximité sémantique moyenne · style neutre.</div>
</div>
<div class="row">
<div>
<label for="latentX">Axe X : <span id="latentXValue">50</span></label>
<input id="latentX" type="range" min="0" max="100" value="50" />
</div>
<div>
<label for="latentY">Axe Y : <span id="latentYValue">50</span></label>
<input id="latentY" type="range" min="0" max="100" value="50" />
</div>
</div>
</div>
</article>
<article class="card" id="workflow">
<div class="card-head">
<div>
<h3>8. Chaîne de traitement</h3>
<p>Le web génératif articule plusieurs opérations en un workflow.</p>
</div>
<span class="tag">workflow</span>
</div>
<div class="ui">
<div class="flow">
<div class="step"><b>1. Entrée</b><span>texte, image, corpus</span></div>
<div class="step"><b>2. Modèle</b><span>inférence ou API</span></div>
<div class="step"><b>3. Paramètres</b><span>style, seuil, format</span></div>
<div class="step"><b>4. Sortie</b><span>résultat ou variantes</span></div>
<div class="step"><b>5. Réemploi</b><span>export, prototype</span></div>
</div>
<div class="output">L’affordance computationnelle réside dans l’enchaînement praticable : saisir, calculer, ajuster, réutiliser.</div>
</div>
</article>
</section>
</main>
<footer class="wrap">
<p>Prototype statique pour un Hugging Face Space. Les cartes 1–5 et 7–8 sont des maquettes interactives ; la carte 6 charge un modèle compatible Transformers.js dans le navigateur.</p>
</footer>
<script>
const $ = (selector, scope = document) => scope.querySelector(selector);
const $$ = (selector, scope = document) => Array.from(scope.querySelectorAll(selector));
function setOutput(id, text, busy = false) {
const el = document.getElementById(id);
if (!el) return;
el.textContent = text;
el.setAttribute("aria-busy", String(busy));
}
function pseudoSentence(prompt) {
const words = prompt.trim().split(/\s+/).filter(Boolean);
const subject = words.slice(0, 4).join(" ") || "La consigne";
return `${subject} devient ici une entrée opératoire. L’interface transforme la demande en chaîne de traitement, puis en résultat médiatique réutilisable.`;
}
document.addEventListener("click", async (event) => {
const button = event.target.closest("[data-action]");
if (!button) return;
const action = button.dataset.action;
if (action === "mock-generate") {
setOutput("promptOut", "Calcul simulé…", true);
window.setTimeout(() => {
setOutput("promptOut", pseudoSentence($("#promptText").value));
}, 420);
}
if (action === "clear-output") {
setOutput(button.dataset.target, "");
}
if (action === "make-gallery") {
$$("#gallery .thumb").forEach((thumb, index) => {
const seed = Math.random().toString(36).slice(2, 4).toUpperCase() + (index + 1);
thumb.dataset.seed = seed;
thumb.style.setProperty("--x", `${12 + Math.random() * 76}%`);
thumb.style.setProperty("--y", `${12 + Math.random() * 76}%`);
thumb.style.setProperty("--angle", `${Math.floor(Math.random() * 180)}deg`);
});
}
if (action === "copy-code") {
const text = $("#apiCode").innerText;
try {
await navigator.clipboard.writeText(text);
setOutput("copyOut", "Fragment copié dans le presse-papiers.");
} catch (error) {
setOutput("copyOut", "Copie impossible dans ce navigateur. Sélectionner le code manuellement.");
}
}
});
function updateParams() {
const temperature = $("#temperature").value;
const tokens = $("#tokens").value;
$("#temperatureValue").textContent = temperature;
$("#tokensValue").textContent = tokens;
setOutput(
"paramOut",
`Paramètres actifs : ${$("#modelSelect").value} · ${$("#formatSelect").value} · température ${temperature} · ${tokens} tokens.`
);
}
["#temperature", "#tokens", "#modelSelect", "#formatSelect"].forEach((selector) => {
$(selector).addEventListener("input", updateParams);
$(selector).addEventListener("change", updateParams);
});
function updateImageParams() {
$("#guidanceValue").textContent = $("#guidance").value;
$("#stepsValue").textContent = $("#steps").value;
}
["#guidance", "#steps"].forEach((selector) => {
$(selector).addEventListener("input", updateImageParams);
});
function updateLatent() {
const x = Number($("#latentX").value);
const y = Number($("#latentY").value);
$("#latentXValue").textContent = x;
$("#latentYValue").textContent = y;
$("#latentDot").style.setProperty("--lx", `${x}%`);
$("#latentDot").style.setProperty("--ly", `${y}%`);
const style = x < 33 ? "documentaire" : x > 66 ? "spéculatif" : "analytique";
const density = y < 33 ? "faible densité" : y > 66 ? "haute densité" : "densité moyenne";
$("#latentLabel").textContent = `Position : style ${style} · ${density} · variation potentielle.`;
}
["#latentX", "#latentY"].forEach((selector) => {
$(selector).addEventListener("input", updateLatent);
});
let classifier = null;
async function getClassifier() {
if (classifier) return classifier;
const { pipeline } = await import("https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.8.1");
classifier = await pipeline(
"sentiment-analysis",
"Xenova/distilbert-base-uncased-finetuned-sst-2-english"
);
return classifier;
}
$("#runSentiment").addEventListener("click", async () => {
const button = $("#runSentiment");
const text = $("#sentimentText").value.trim();
if (!text) {
setOutput("sentimentOut", "Ajouter un texte à analyser.");
return;
}
button.disabled = true;
setOutput("sentimentOut", "Chargement du modèle et analyse en cours…", true);
try {
const pipe = await getClassifier();
const result = await pipe(text);
const first = Array.isArray(result) ? result[0] : result;
const percent = Math.round((first.score || 0) * 100);
setOutput("sentimentOut", `Résultat : ${first.label} · confiance ${percent} %. Le traitement a été exécuté côté navigateur.`);
} catch (error) {
console.error(error);
setOutput("sentimentOut", "Erreur de chargement ou d’exécution. Vérifier la connexion, le navigateur et la disponibilité du modèle.");
} finally {
button.disabled = false;
}
});
$("#resetSentiment").addEventListener("click", () => {
$("#sentimentText").value = "I find this browser-based interface useful and surprisingly clear.";
setOutput("sentimentOut", "Le modèle sera téléchargé au premier usage. Le calcul s’exécute ensuite dans le navigateur.");
});
</script>
</body>
</html>