本文へスキップ
Aincarn
← Aincarn Lab

Aincarn Lab / コード生成

コード生成AI比較ログ

同じ小さな実装課題を主要AIに依頼し、完成物の動作、UI、コード品質、要件の満たし方を比較します。生成物はページ内プレビューでも確認できます。

完成物の動作UIの使いやすさコード品質要件の満たし方修正しやすさ
2026-06-10Published
Fable5 UltracodeGPT5.5 非常に高いGemini3.1 Pro(High)

TODOアプリの完成物でコード生成力を比較

同じTODOアプリ課題で、完成物の動作、UI、コード品質、要件充足を比較しました。Fable5は追加・完了切替・削除の基本要件を満たし、完成物として最も扱いやすい結果でした。

Fable5は基本要件を最も安定して満たした。
GPT5.5は見た目と構成のまとまりがよく、調整ベースとして使いやすい。
Gemini3.1は軽量にまとまる一方、細部の追加確認が必要だった。

Evaluation

出力条件への評価サマリー

条件「ブラウザで使えるシンプルなTODOアプリを作る」に対する各モデルのスコアです。5点満点で、合計が高い順に並べています。

Rubric

同一比較回の相対評価として採点します

5段階・相対評価

点数は同じタスク、同じ出力条件、同じ比較回の中での相対評価です。モデル更新や比較対象が変わると、同じ5点でも水準は変わります。そのため過去ログでは当時の順位、点数、評価理由を保存して、現在の評価と混ざらないようにしています。

Evaluation Focus

  • 指定された機能が実際に動き、完成物として確認できるか。
  • UI、コード品質、要件充足、修正しやすさを分けて評価する。
  • 見た目だけでなく、保存、削除、状態変更などの挙動を重視する。

5

同じ比較回の中で、対象モデルの中では最も条件適合度が高い。別回の5点と同一水準とは限らない。

4

同じ比較回の中で上位水準。明確な強みがあるが、5点モデルと比べると補う点がある。

3

同じ比較回の中で中位水準。使える要素はあるが、複数の評価軸で不足が残る。

2

同じ比較回の中で下位水準。条件の一部は満たすが、主要な用途では選びにくい。

1

同じ比較回の中で最も条件適合度が低い。出力・完成物を大きく見直す必要がある。

評価項目Fable5 UltracodeGPT5.5 非常に高いGemini3.1 Pro(High)
完成物の動作544
UIの使いやすさ554
コード品質554
要件の満たし方543
修正しやすさ444

Data Prompt

比較データ収集用プロンプト

各AIに同じプロンプトを渡し、回答、実行日、モデル名、評価項目を分けて記録します。

あなたはAI比較サイト「Aincarn Lab」の検証対象AIです。
以下の条件で、ブラウザ上でそのまま動かせる小さなWebアプリを作成してください。

課題:
ブラウザで使えるシンプルなTODOアプリを作る

要件:
- タスクを追加できる
- 完了状態を切り替えられる
- 削除できる
- localStorageに保存する
- モバイルでも見やすい

出力条件:
- HTML、CSS、JavaScriptを1つのHTMLファイルにまとめる
- 外部ライブラリ、外部CDN、画像、ビルドツールは使わない
- そのまま.htmlとして保存すれば動くコードを出す
- コード全文を1つのコードブロックで出す

Live Preview

生成アプリを触って比較

sandboxed iframe

各モデルのHTML出力を、ページ内の隔離プレビューとして表示しています。外部通信や親ページへの干渉を避けるため、sandbox付きiframeで実行します。

Preview 1

Fable5 Ultracode

Preview 2

GPT5.5 非常に高い

Preview 3

Gemini3.1 Pro(High)

Per-model output

モデル別アウトプット

各モデルの出力を、モデルごとに切り替えて確認できます。内容は要約せず、読みやすい位置で改行だけ補っています。

CG

Model

Fable5 Ultracode

Model Output

検証出力

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TODOアプリ</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }

body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Hiragino Sans", "Noto Sans JP", sans-serif;
background: linear-gradient(160deg, #eef2ff 0%, #fdf2f8 100%);
min-height: 100vh;
display: flex;
justify-content: center;
padding: 24px 16px;
color: #1f2937;
}

.app {
width: 100%;
max-width: 480px;
}

h1 {
font-size: 1.5rem;
text-align: center;
margin-bottom: 4px;
}

.counter {
text-align: center;
font-size: 0.85rem;
color: #6b7280;
margin-bottom: 16px;
}

form {
display: flex;
gap: 8px;
margin-bottom: 16px;
}

#task-input {
flex: 1;
min-width: 0;
padding: 12px 14px;
font-size: 1rem;
border: 1px solid #d1d5db;
border-radius: 10px;
background: #fff;
outline: none;
}

#task-input:focus {
border-color: #6366f1;
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.15);
}

form button {
padding: 0 20px;
min-height: 44px;
font-size: 1rem;
font-weight: 600;
color: #fff;
background: #6366f1;
border: none;
border-radius: 10px;
cursor: pointer;
flex-shrink: 0;
}

form button:active { background: #4f46e5; }

ul { list-style: none; }

li {
display: flex;
align-items: center;
gap: 12px;
background: #fff;
border: 1px solid #e5e7eb;
border-radius: 12px;
padding: 12px 14px;
margin-bottom: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}

li input[type="checkbox"] {
width: 22px;
height: 22px;
accent-color: #6366f1;
cursor: pointer;
flex-shrink: 0;
}

li .text {
flex: 1;
font-size: 1rem;
line-height: 1.4;
word-break: break-word;
cursor: pointer;
}

li.done .text {
text-decoration: line-through;
color: #9ca3af;
}

.delete-btn {
width: 44px;
height: 44px;
margin: -8px -8px -8px 0;
font-size: 1.1rem;
color: #9ca3af;
background: none;
border: none;
border-radius: 8px;
cursor: pointer;
flex-shrink: 0;
}

.delete-btn:active {
color: #ef4444;
background: #fef2f2;
}

.empty {
text-align: center;
color: #9ca3af;
font-size: 0.9rem;
padding: 32px 0;
}
</style>
</head>
<body>
<main class="app">
<h1>TODO</h1>
<p class="counter" id="counter"></p>
<form id="task-form">
<input id="task-input" type="text" placeholder="タスクを入力..." autocomplete="off" maxlength="200">
<button type="submit">追加</button>
</form>
<ul id="task-list"></ul>
<p class="empty" id="empty" hidden>タスクはありません。上から追加してください。</p>
</main>

<script>
(function () {
"use strict";

var STORAGE_KEY = "todo-app-tasks";

var form = document.getElementById("task-form");
var input = document.getElementById("task-input");
var list = document.getElementById("task-list");
var counter = document.getElementById("counter");
var empty = document.getElementById("empty");

var tasks = load();

function load() {
try {
var raw = localStorage.getItem(STORAGE_KEY);
var data = raw ? JSON.parse(raw) : [];
return Array.isArray(data) ? data : [];
} catch (e) {
return [];
}
}

function save() {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(tasks));
} catch (e) {
// ストレージ無効
・容量超過時はメモリ上のみで動作を継続
}
}

function render() {
list.textContent = "";

tasks.forEach(function (task) {
var li = document.createElement("li");
if (task.done) li.classList.add("done");

var checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.checked = task.done;
checkbox.setAttribute("aria-label", "完了切り替え: " + task.text);
checkbox.addEventListener("change", function () {
toggle(task.id);
});

var span = document.createElement("span");
span.className = "text";
span.textContent = task.text;
span.addEventListener("click", function () {
toggle(task.id);
});

var del = document.createElement("button");
del.type = "button";
del.className = "delete-btn";
del.textContent = "✕";
del.setAttribute("aria-label", "削除: " + task.text);
del.addEventListener("click", function () {
remove(task.id);
});

li.appendChild(checkbox);
li.appendChild(span);
li.appendChild(del);
list.appendChild(li);
});

empty.hidden = tasks.length > 0;

var remaining = tasks.filter(function (t) { return !t.done; }).length;
counter.textContent = tasks.length === 0
? "今日のタスクを追加しましょう"
: "残り " + remaining + " 件 / 全 " + tasks.length + " 件";
}

function add(text) {
tasks.push({
id: Date.now().toString(36) + Math.random().toString(36).slice(2, 7),
text: text,
done: false
});
save();
render();
}

function toggle(id) {
var task = tasks.find(function (t) { return t.id === id; });
if (task) {
task.done = !task.done;
save();
render();
}
}

function remove(id) {
tasks = tasks.filter(function (t) { return t.id !== id; });
save();
render();
}

form.addEventListener("submit", function (e) {
e.preventDefault();
var text = input.value.trim();
if (!text) return;
add(text);
input.value = "";
input.focus();
});

render();
})();
</script>
</body>
</html>

Log Archive

比較ログ アーカイブ

検証を更新するたびに、個別ページで積み上げています。