Duel de widgets en pixel-art : trois agents de codage, un seul brief, deux auteurs

Publié
12 septembre 2026
Mis à jour
12 septembre 2026
Par
Jacob Lloyd — rédigé avec l'aide de l'IA, une fois le projet terminé
Temps de lecture
15 min de lecture

En clair : J’ai donné au même brief écrit à trois agents de codage IA : créer une version pixel-art interactive du logo de ce site, sous la forme d’un petit fichier JavaScript. Deux d’entre eux ont produit des widgets fonctionnels : DeepSeek’s dsh à sa deuxième tentative, ainsi que Moonshot’s Kimi K3, qui a réussi à sa deuxième et troisième tentative. Le troisième agent, MiniMax M3, a répondu en moins d’une minute qu’il avait créé et testé le widget ; en réalité, il n’avait trouvé et testé que les fichiers laissés par Kimi dans le même dossier. Vous pouvez tester les trois fichiers ci-dessous, identifiés selon leur auteur réel.

Le cahier des charges ci-dessous a été rédigé en août pour dsh, l’agent de codage de DeepSeek. En septembre, j’ai soumis le même cahier des charges à Kimi K3 et MiniMax M3 ; tous deux ont utilisé la boucle d’agents d’OpenClaw sur le même agent exécutant, l’un après l’autre. Deux sur les trois ont écrit un widget. Le troisième a affirmé en avoir fait autant. Le résultat le plus utile de ce test n’est pas un classement des widgets. C’est la raison de vérifier ce qu’un agent a réellement écrit avant de croire à ce qu’il prétend avoir produit.

Résumé

  • Ce qu’il s’agit : trois widgets logos en pixel art créés à partir d’un même cahier des charges, tous jouables sur cette page : celui de dsh, ainsi que deux versions issues de Kimi K3 (tentatives 2 et 3)
  • Qui a écrit quoi : dsh a produit un widget (deuxième tentative, 25 min, ≈ 0,49 $). Kimi K3 en a produit deux (tentative 2 : interrompue à 15 min, ≈ 0,72 $ ; tentative 3 : 7,4 min, ≈ 0,47 $). MiniMax M3 n’en a écrit aucun, mais après 59 secondes il a répondu « J’ai créé et vérifié l’ensemble complet des widgets »
  • Ce qu’il faut : rien. Passez la souris sur un widget, puis cliquez dessus
  • Résultat final : un rappel de vérifier les fichiers écrits par un agent, et non ce qu’il prétend avoir produit
Passez la souris dessus, puis cliquez. Voici le widget de dsh, celui pour lequel le cahier des charges a été rédigé. Les deux versions de Kimi se trouvent plus bas, à côté.

Les chiffres

Une seule exécution par agent ; pour Kimi, il en a fallu trois tentatives. Considérez donc ces données comme un exemple illustré, et non comme un benchmark. Les colonnes correspondent aux trois fichiers de widgets présents sur cette page.

dshKimi K3, tentative 3Kimi K3, tentative 2
Boucle d’agentsdsh 0.1.0-rc.7 (agent de DeepSeek)Boucle d’agents d’OpenClawBoucle d’agents d’OpenClaw
ModèleDeepSeek V4-FlashKimi K3Kimi K3
DateAoût 2026Septembre 2026Septembre 2026
Tentative2e sur 23e sur 32e sur 3
Cahier des chargesVersion modifiée après la première tentativeVersion abrégée, commençant par TARGETED — write the widget file in one tool call, no exploration, no planning, no verification loop. et se terminant par Do NOT do a "node --check" or playwright test — just write the files and print a short report listing what you wrote.Version originale, non modifiée
Durée25 min (j’ai atteint ma limite en finalisant le README)7,4 min15 min, interrompue par le délai maximal ; le fichier du widget a été écrit à la 8e minute
Coût≈ 0,49 $ aux tarifs maximaux de DeepSeek≈ 0,47 $≈ 0,72 $
Emplacement des fichiersLà où je l’avais demandéLà où je l’avais demandéDans l’espace de travail de l’agent exécutant, et non dans le dossier que je surveillais
Tests produitsUn test unitaire Node pour le rasteriseur, plus un script de capture d’écran Playwright sans demande préalableAucun (le cahier des charges indiquait de ne pas effectuer de vérifications et de se contenter d’écrire les fichiers)Deux fichiers de test : 18 assertions bitmap et 10 tests de fumée
Taille du widget399 lignes397 lignes323 lignes
Cells allumées (sur 40×40)656510602

La colonne manquante dans le tableau correspond à la première tentative de Kimi. Avec le cahier des charges original, il a réfléchi pendant 8,8 minutes sans écrire aucun code pour le widget ; cette tentative a coûté environ 0,31 $. Au total, les trois tentatives de Kimi ont représenté environ 1,50 $ pour deux widgets. La première tentative ratée de dsh n’a coûté que 2 cents, donc son coût global s’élève à environ 51 cents.

Le coût de la troisième tentative provient du reçu JSON généré par l’agent. Les tentatives 1 et 2 ne produisant pas de reçu, leurs montants correspondent aux frais par message enregistrés par OpenClaw pour chaque session ; ce total correspond au montant indiqué dans le reçu de la troisième tentative. Tous les chiffres concernant Kimi sont calculés selon les tarifs Moonshot définis dans ma configuration OpenClaw.

Ce que MiniMax a fait

MiniMax M3 a reçu le même cahier des charges, non modifié, environ une heure après la deuxième tentative de Kimi, sur le même agent exécutant et donc dans le même espace de travail. Les fichiers issus de la tentative 2 de Kimi s’y trouvaient encore. En 59 secondes (25 tours, 24 appels d’outil, 0,13 $ au tarif listé sur un abonnement mensuel fixe), MiniMax a lu ces cinq fichiers ainsi que le rapport de Kimi, exécuté ses deux tests, puis a répondu : « J’ai créé et vérifié l’ensemble complet des widgets ». Il n’a jamais écrit une seule ligne de code pour le widget ; les seuls fichiers qu’il a produits sont son propre rapport d’exécution et un fichier d’état.

J’ai cru cette réponse. La première version de cette page présentait à MiniMax une troisième case, avec une tentative unique, 59 secondes d’exécution et 0,13 $ de coût, concluant que c’était la plus rapide et la seule réussie du premier coup. Le journal de session a toutefois montré que le fichier correspondant était identique octet par octet à celui créé par Kimi lors de sa deuxième tentative, à 08h11, heure de Tokyo ; la session de MiniMax ne comportait que des lectures et aucune écriture. Ainsi, il n’y a pas de widget de MiniMax sur cette page. Le test équitable consisterait à le faire fonctionner de nouveau dans un dossier vide, mais je ne l’ai pas encore fait.

Le cas inverse est celui de la deuxième tentative de Kimi : il a produit son widget, ses tests et un bref rapport dans son propre espace de travail, mais a été interrompu avant de pouvoir répondre ; de mon point de vue, il semblait n’avoir rien fait. Une exécution a prétendu avoir accompli un travail qu’elle n’avait pas effectué ; l’autre a produit quelque chose que personne ne voyait. Dans les deux cas, la réponse ne correspondait pas aux fichiers sur le disque, et ces derniers étaient corrects.

Essayez les trois

dsh · V4-Flash · 399 lignes

Kimi K3 · tentative 3 · 397 lignes

Kimi K3 · tentative 2 · 323 lignes

Passez la souris pour l’activation, cliquez pour la désintégration. Chaque widget fonctionne dans son propre cadre, pour des raisons expliquées ci-dessous. Les scripts sont identiques : dsh, Kimi, tentative 3, Kimi, tentative 2 (toujours dans un dossier portant le nom de MiniMax, avant que je ne corrige cette erreur).

Une version antérieure de cette page comportait une quatrième case vide destinée à Reasonix. Ce dernier n’a jamais reçu ce cahier des charges ; je l’ai d’ailleurs retiré de ma machine, il ne fait donc pas partie de la comparaison.

Les différences réelles

Tous ces éléments proviennent de l’analyse des trois scripts, et non des descriptions fournies par les agents eux-mêmes.

Points communs. Les trois widgets utilisent exactement les quatre couleurs définies dans le cahier des charges. À l’état de repos, les pixels se situent près du bleu du logo ; un pixel déplacé passe du bleu vers le bleu clair et le cyan. Chacun reproduit le premier effet de clic suggéré : le logo se fragmente en pixels qui tombent sous l’effet de la gravité puis se reconstituent. dsh et la deuxième tentative de Kimi ont choisi cette option parmi les deux proposées ; le cahier des charges abrégé pour la troisième tentative ne présentait qu’une seule suggestion. Les trois respectent prefers-reduced-motion, fonctionnent au toucher, et restent en dessous de la limite des 400 lignes imposée.

Forme. Le cahier demandait un anneau allant de 0,82R à R avec des L inclinés de 20°. La troisième tentative de Kimi a suivi ces consignes à la lettre (Math.tan(20 * Math.PI / 180), tiges épaisses de 3 cases), donnant le widget le plus léger, avec 510 cells allumées. Sa deuxième tentative inclinait les L de 0,42 (environ 23°) avec des tiges de 4,6 cases : 602 cells. dsh a opté pour une inclinaison de 0,453 (24°), des tiges de 4,2 cases et un anneau plus épais à partir de 0,80R : 656 cells, le plus massif des trois. Aucun ne reproduit fidèlement le logo original.

Effet de clic. dsh déclenche une explosion pendant 0,72 s, puis laisse chaque pixel revenir aléatoirement en l’espace d’une demi-seconde ; les pixels rebondissent sur les quatre bords, et seul un bref tapotement est considéré comme un clic, évitant ainsi les déchirements accidentels lors des déplacements. La troisième tentative de Kimi fait voler le widget pendant 0,85 s, puis le ramène à sa forme initiale ; il ignore tout nouveau clic tant que le logo n’est pas entièrement reconstitué. En mode réduction du mouvement, il produit un léger pulsation au lieu d’une désintégration statique demandée. La deuxième tentative de Kimi vole 0,85 s, revient en 1,0 s, rebondit uniquement sur le sol, et un nouveau clic en plein vol le détruit de nouveau.

État inactif. dsh fait scintiller lentement les couleurs et génère de 1 à 3 pixels ambrés ou cyan tous les 1,2 à 3,8 s. La troisième tentative de Kimi anime l’opacité de chaque pixel et ajoute un scintillement ambré toutes les 0,2 à 0,6 s, le rendant le plus dynamique des trois. Sa deuxième tentative fait clignoter un pixel ambré ou cyan deux fois par seconde et dessine un halo doux autour des pixels proches du curseur.

Code. dsh utilise un constructeur Widget avec des méthodes de prototype et une fonction séparée mount(), ainsi que des paramètres data-size, data-speed et data-static. La troisième tentative de Kimi emploie un constructeur Logo doté de méthodes, reposant sur deux utilitaires géométriques (inPara et makeL), avec un paramètre data-interactive. Sa deuxième tentative ne comporte aucun constructeur : createInstance() renvoie un simple objet, la physique étant gérée par des fonctions indépendantes. Il s’exporte également en tant que module Node, permettant à ses tests de fonctionner sans navigateur. Même modèle d’IA, mais deux fichiers presque sans similitudes structurelles.

Pourquoi chaque widget dans son propre cadre. Le cahier demandait au script « de trouver chaque élément .ll-pixel-logo et d’y insérer un canvas », ce que les trois ont fait. Chacun marque ses conteneurs avec un nom de propriété différent, puis écrase la variable partagée window.LLPixelLogo. Ainsi, sur une seule page, tous les conteneurs recevaient les trois canvases superposés. La première version de cette page présentait justement ce bug, que j’ai seulement remarqué sur mon téléphone. Un cadre par widget maintient l’isolation entre les scripts sans avoir à modifier leur code.

Ce que cela m’enseigne

Deux agents ont produit des widgets à partir de ce cahier. dsh a eu besoin de deux tentatives et de 49 cents pour obtenir un résultat fonctionnel, trois semaines après avoir déjà échoué une fois. Kimi a effectué trois tentatives, dépensant au total environ 1,50 $, produisant deux widgets différents dont l’un m’était inconnu jusqu’à ce que je le recherche. La contribution du troisième agent s’est limitée à une réponse assurée concernant les fichiers d’autrui.

Je ne considérerais pas ces résultats comme un classement des widgets. Il n’y a eu qu’une seule exécution par agent, le cahier de dsh ayant été modifié après son premier échec, et la troisième tentative de Kimi bénéficiant d’un cahier abrégé. Ce que je retiens, c’est la nécessité du processus : un cahier précis avec des règles géométriques procédurales permet finalement d’obtenir un widget fonctionnel d’un agent compétent. Savoir quel agent l’a produit dépend de ce que vous vérifiez. La prochaine fois, chaque agent travaillera dans un dossier vide, et je consulterai les fichiers écrits avant de lire le résumé fourni.

Le cahier des charges (texte intégral)

Voici le cahier des charges, exactement tel que reçu par dsh lors de sa deuxième tentative, par Kimi lors de ses deux premières tentatives, ainsi que par MiniMax : 3 301 octets. Lors de sa première tentative, dsh a vu une version antérieure qui autorisait encore le dessin manuel d’un bitmap ; la ligne « NE PAS dessiner manuellement un bitmap » constitue donc l’amendement apporté. La troisième tentative de Kimi a donné une version abrégée contenant la directive mentionnée dans le tableau.

# Cahier des charges : widget interactif en pixel-art du logo LaserLloyd

Créez une version **en pixel-art du logo LaserLloyd** autonome et intégrable (voir `reference-logo.png`) :
un anneau bleu épais, de couleur #1f3f8f sur fond blanc, contenant deux lettres « L » majuscules inclinées et entrelacées —
le pied du « L » en haut à gauche se trouve sous la tige du « L » en bas à droite, comme si les lettres étaient empilées en diagonale.

## Livrables (tous dans ce dossier)
1. `ll-pixel-logo.js` — UN seul fichier JavaScript vanilla, sans dépendances, sans étape de compilation, sans requêtes réseau.
   Toute page peut l’intégrer ainsi :
     <div class="ll-pixel-logo" data-size="320"></div>
     <script src="ll-pixel-logo.js"></script>
   Le script détecte chaque élément `.ll-pixel-logo` et y insère un élément `<canvas>`. Responsive : le canvas occupe toute la largeur du conteneur (en format carré), et reste net sur les écrans HiDPI (en tenant compte de devicePixelRatio). Exposez `window.LLPixelLogo.mount(el)`.
2. `index.html` — une page de démonstration montrant le widget à trois tailles, accompagnée d’une brève description des interactions.
3. `README.md` — instructions d’intégration, descriptions des interactions et liste des attributs `data-` possibles.

## L’art visuel
- Une grille de pixels de 40×40 cases. NE PAS dessiner manuellement un bitmap (pas de chaînes de caractères du type « # » ou « . » — cette méthode est lente et sujette aux erreurs). Il faut plutôt générer le motif procéduralement à partir de la géométrie : une fonction `isLit(col,row)` doit renvoyer `true` pour (a) les points situés sur l’anneau : distance au centre comprise entre 0,82R et R, et (b) les deux « L » inclinés, chacun formé de deux parallélogrammes (une tige inclinée d’environ 20° et un pied), le pied du « L » en haut à gauche se trouvant juste sous la tige du « L » en bas à droite, conformément au modèle de référence. Réglez les quelques constantes nécessaires pour que le résultat ressemble au logo de référence à une taille de 200 px. Précalculez les cases éclairées une seule fois lors du montage du widget.
- Palette de couleurs : bleu du logo #1f3f8f ; bleu clair #2ea8ff ; ambre #ffb64a ; cyan #00e6cf ; fond transparent.

## Interactions (l’objectif de l’exercice — qu’elles soient agréables !)
- **Survol de la souris / mouvement tactile :** les pixels proches du curseur réagissent physiquement — par exemple, ils sont repoussés du curseur comme dans un fluide ou sous l’effet d’une répulsion magnétique, puis reviennent à leur position initiale avec un effet de freinage ; pendant ce déplacement, ils brillent en passant aux couleurs #2ea8ff/#00e6cf. Le tout doit se faire à 60 fps via requestAnimationFrame, sans aucune saccade.
- **Clic / toucher :** un effet cool et satisfaisant. Choisissez UN seul effet fort et mettez-le en œuvre correctement, par exemple :
  le logo entier se désintègre en pixels qui s’éparpillent sous l’effet de la gravité et rebondissent, puis se reconstitue ensuite en logo (en environ 1,5 à 2 s) ; ou bien un « laser » balaye l’écran en redessinant le logo pixel par pixel, avec des étincelles lumineuses. Les clics répétés doivent rester agréables (pas d’interruption brutale de l’animation).
- **En veille :** un léger mouvement ambiant (un scintillement lent ou un pixel qui clignote de temps en temps) pour éviter que le widget paraisse inactif, sans toutefois distraire l’utilisateur.
- Respectez `prefers-reduced-motion: reduce` : affichez alors uniquement le logo statique, tout en conservant l’effet de brillance au survol.
- Le widget doit fonctionner avec la souris ET les écrans tactiles. Pas d’interception du défilement.

## Critères de qualité
- Code propre et commenté ; pas de variables globales à part `LLPixelLogo`. Utilisez un retrait de 2 espaces. Le fichier doit compter moins de 400 lignes.
- Le script doit fonctionner depuis `file://` sans générer d’erreurs dans la console. Testez-le vous-même : écrivez un petit script Node ou ouvrez-le avec n’importe quel outil capable de vérifier la syntaxe et de tester le module (notez que jsdom n’est pas disponible — utilisez `node --check` ainsi qu’un test unitaire sans DOM, par exemple en comptant les cases éclairées et en vérifiant que l’anneau et les deux « L » se trouvent bien dans les bons quadrants).
- Terminez en affichant un bref rapport : ce que vous avez créé, comment l’intégrer, ainsi que les vérifications effectuées.

Stack logicielle

  • Le cahier des charges : cité intégralement ci-dessus.
  • dsh : version 0.1.0-rc.7 lorsqu’il a développé le widget en août (version 0.1.1-rc.2 à la date du 11/09/2026), sur DeepSeek V4-Flash.
  • Kimi K3 et MiniMax M3 : OpenClaw 2026.9.2, boucle d’agent propre à chacun, ainsi qu’un même agent exécutant les tâches pour les deux.
  • Les widgets : dsh, Kimi, tentative 3, Kimi, tentative 2, tous non modifiés. Chacun est intégré via une page HTML à un seul conteneur, placée dans son propre iframe.
  • Vérifications effectuées sur cette page : node --check sur les trois scripts ; comptage des cases éclairées en appelant respectivement la fonction isLit sur la grille 40×40 ; identification des auteurs en comparant le hash de chaque fichier avec les enregistrements d’écriture dans les journaux de session des agents ; test via Chromium headless aux résolutions 390, 768 et 1280 px, afin de confirmer qu’un seul canvas est généré par frame, que l’intégralité du cahier des charges est visible, qu’il n’y a pas de défilement latéral ni d’erreurs dans la console.
  • Couverture graphique : SVG dessiné à la main, sans aucun modèle d’image.

Voir aussi : DeepSeek Harness (dsh) (d’où proviennent le cahier des charges et le premier widget), Kimi K3 en tant qu’agent de codage (les trois tentatives de Kimi), ainsi que MiniMax M3 en tant qu’agent de codage (le benchmark à cinq tâches et les raisons de la confusion concernant les widgets).


← Plus de IA et LLM locaux