{
  "title": "Бенчмарк LLM: 3D-сцена на three.js",
  "headline": "3D-сцена на three.js",
  "date": "29-10-2026",
  "tests_total": 164,
  "perf_total": 3,
  "oracle": "эталонная сборка сцены",
  "oracle_note": "three.js r186, Node 24",
  "lede": "Модели пишут на JavaScript модуль для three.js, который превращает JSON-описание в 3D-сцену: иерархию объектов с поворотами и масштабом, примитивы, выдавленные контуры, тысячи экземпляров, свет и камеру. Каждую сцену сравнивают с эталоном по мировым матрицам, габаритам, цветам и попаданиям лучей из камеры.",
  "segments": {
    "hand": "ручных сцен",
    "rand": "случайных сцен",
    "err": "описаний с ошибкой"
  },
  "gallery": {
    "title": "Как модели построили контрольную сцену",
    "caption": "Одна и та же сцена, отрендеренная WebGL в Chrome без окна одним и тем же рендерером. Отличаются только сами сцены, которые построил код модели. Переключатель «Отличия от эталона» подсвечивает красным пиксели, которые не совпали.",
    "reference_note": "так должно получиться"
  },
  "scene": {
    "title": "Контрольная сцена в 3D",
    "lede": "Та же сцена, что в галерее, но живая: её прямо в браузере строит опубликованный код модели и эталонная реализация стенда. Сцену можно покрутить и сравнить с эталоном с любой стороны, а ниже подставить своё описание.",
    "spec": "gallery/showcase.json",
    "reference": "harness/reference.mjs"
  },
  "task": {
    "name": "сборщик 3D-сцены на three.js",
    "file": "task/task.md",
    "summary": "Нужно написать ES-модуль с функцией `buildScene(THREE, spec)`, которая возвращает `{ scene, camera }`. Описание задаёт дерево узлов с позицией, поворотом в градусах и порядком Эйлера, масштабом (в том числе отрицательным) и `lookAt`, примитивы `box`, `sphere`, `cylinder`, `torus`, `plane`, выдавленные контуры с отверстиями, `InstancedMesh`, три вида света и перспективную или ортографическую камеру. Цвета задаются в sRGB.",
    "checks": [
      "38 ручных сцен с ловушками. Среди них градусы вместо радиан, порядки поворота `YXZ` и `ZYX`, глубокая иерархия с масштабом, отрицательный масштаб, `lookAt`, который у обычного объекта направляет к цели ось +Z, а у камеры ось −Z, `lookAt` внутри повёрнутого родителя и у родителя с потомком, цвет `#ff8800`, который three.js хранит в линейном пространстве, короткие записи цвета, контур с отверстием, пустой список экземпляров, цель направленного света, ортографическая камера и камера с осью `up`.",
      "120 случайных сцен из генератора с фиксированным seed: деревья до четырёх уровней из всех типов узлов, случайные повороты, порядки, масштабы, `lookAt`, прозрачность, невидимые объекты, свет и камеры.",
      "6 описаний, которые обязаны закончиться исключением: неизвестный тип, неверный цвет, цвет из четырёх цифр, контур из двух точек, неизвестный порядок поворота, неизвестная геометрия экземпляров.",
      "3 замера скорости: 3000 объектов с `lookAt`, цепочка из 1500 вложенных групп с `lookAt` и 50 000 экземпляров. На каждый даётся 2 секунды, эталон укладывается в 0,11 секунды.",
      "Каждая сцена сравнивается с эталоном по всем именованным объектам: тип, родитель, видимость, мировая матрица, число вершин и габариты в мире, цвет, прозрачность и сторона материала, матрицы экземпляров, параметры света. У камеры сравниваются матрица проекции и положение. Затем из камеры пускаются 63 луча, и для каждого первый задетый объект должен совпасть с эталоном.",
      "Сам стенд проверен эталоном: 164 сцены из 164 и все три замера."
    ]
  },
  "conditions": [
    "Участвуют модели, которые дали рабочий код в предыдущих тестах. Каждая получила задание слово в слово, одним сообщением, без системного промпта и без инструментов, и не могла запустить свой код.",
    "Параметры рассуждения такие же, как раньше: у Qwen включён `enable_thinking`, у GPT `reasoning_effort: high`, Opus через API получал `thinking: adaptive` и `effort: max` через нативный `/messages` партнёрского шлюза, Kimi и DeepSeek работали в режиме по умолчанию.",
    "Opus 5.5 дополнительно решал задачу агентом Claude Code с чистым контекстом: одно чтение задания и одна запись решения, без запуска кода.",
    "Grok 4.7 не участвует: в двух прошлых тестах партнёрский шлюз обрывал все его попытки.",
    "В зачёт идёт код как есть. Вариант с правкой одной строки считается отдельно, только для понимания."
  ],
  "nuances": [
    "Задание заканчивалось фразой «Ответь ТОЛЬКО кодом модуля». Для моделей с адаптивным мышлением она оказалась невыгодной, это видно по Opus через API. Начиная со следующего теста задания заканчиваются фразой «Сначала продумай решение, затем ответь модулем».",
    "Проверка шлюза: на задаче-головоломке Opus с `effort: low` думал 700 токенов, с `max` 19 тысяч. Значит, `effort` доходит до модели, и дело не в коннекторе.",
    "Диагностические прогоны Opus с другой формулировкой в рейтинг не входят, в рейтинге прогон по общему заданию.",
    "Все замеры скорости уложились с большим запасом, поэтому места среди решений без ошибок условны: разница во времени замеров на уровне погрешности.",
    "Галерея рендерится одним и тем же кодом WebGL в Chrome без окна (SwiftShader). Отличия на картинках бывают только от разной сцены, которую построила модель.",
    "Время и токены Opus-агента оценочные, по объёму кэша контекста. Протокол агента проверен: одно чтение задания и одна запись решения.",
    "Opus-агент с `effort: max` добавлен 29.10.2026, после основного прогона, по тому же протоколу: одно чтение задания и одна запись решения, без запуска кода. Его запустили, чтобы сравнить с Opus через API на том же `effort: max`: через партнёрский шлюз модель рассуждает заметно меньше."
  ],
  "participants": [
    {
      "id": "opusagent",
      "name": "Claude Opus 5.5 (агент)",
      "vendor": "Anthropic",
      "model": "claude-opus-5-5",
      "access": "субагент Claude Code, чистый контекст, без запуска кода",
      "max_tokens": null,
      "answer": null,
      "grade": "grades/opusagent.txt",
      "solution": "solutions/opusagent/solution.mjs",
      "seconds": 159.7,
      "out_tokens": 13000,
      "reasoning_tokens": 8500,
      "reasoning_estimated": true,
      "verdict": "164 сцены из 164 и все три замера скорости. Решение заняло 2 минуты 40 секунд и 277 строк. Агент работал вслепую: одно чтение задания, одна запись решения, код не запускался (протокол проверен). Это третий тест подряд, где Opus-агент проходит всё. Свои допущения агент перечислил в отчёте сам, и все они совпали с эталоном."
    },
    {
      "vendor": "Anthropic",
      "model": "claude-opus-5-5",
      "access": "субагент Claude Code, `effort: max`, чистый контекст, без запуска кода",
      "max_tokens": null,
      "answer": null,
      "reasoning_estimated": true,
      "id": "opusagentmax",
      "name": "Claude Opus 5.5 (агент, effort max)",
      "grade": "grades/opusagentmax.txt",
      "solution": "solutions/opusagentmax/solution.mjs",
      "seconds": 724.8,
      "out_tokens": 83700,
      "reasoning_tokens": 80800,
      "verdict": "164 сцены из 164 и все три замера скорости. Ответ занял 12 минут, на рассуждение ушло около 81 тысячи токенов. Opus через API на том же `effort: max` не рассуждал вовсе и прошёл 158 сцен, так что разница в шесть сцен целиком объясняется размышлением. Протокол соблюдён: одно чтение задания и одна запись решения."
    },
    {
      "id": "kimi",
      "name": "Kimi K3.1 Pro",
      "vendor": "Moonshot AI",
      "model": "kimi-k3.1-pro",
      "access": "API api.moonshot.ai (через VPN роутера)",
      "max_tokens": 128000,
      "answer": "answers/kimi.json",
      "grade": "grades/kimi.txt",
      "solution": "solutions/kimi/solution.mjs",
      "verdict": "164 сцены из 164 и все три замера скорости. Ответ занял 12 минут, из них около 17 тысяч токенов рассуждения. Код 340 строк. Третий тест подряд у Kimi без ошибок или почти без них."
    },
    {
      "id": "qwen",
      "name": "Qwen3.8-Max",
      "vendor": "Alibaba",
      "model": "qwen3.8-max",
      "access": "API token-plan.maas.qwencloudapi.com",
      "max_tokens": 131072,
      "answer": "answers/qwen.json",
      "grade": "grades/qwen.txt",
      "solution": "solutions/qwen/solution.mjs",
      "verdict": "164 сцены из 164 и все три замера скорости, причём самые быстрые: 0,01, 0,02 и 0,01 секунды. Зато ответ занял больше всех, 34 минуты: около 81 тысячи токенов рассуждения при скорости около 40 токенов в секунду. Код 446 строк."
    },
    {
      "id": "gpt",
      "name": "GPT-6.1 Sol",
      "vendor": "OpenAI",
      "model": "gpt-6.1-sol",
      "reasoning_hidden": true,
      "access": "партнёрский шлюз, `reasoning_effort: high`",
      "max_tokens": 128000,
      "answer": "answers/gpt.json",
      "grade": "grades/gpt.txt",
      "solution": "solutions/gpt/solution.mjs",
      "verdict": "164 сцены из 164 и все три замера скорости. Ответ пришёл за 5 минут 10 секунд, рассуждение провайдер не показывает. Код самый длинный среди безошибочных, 414 строк."
    },
    {
      "id": "dsflash",
      "name": "DeepSeek Flash (V4.1)",
      "vendor": "DeepSeek",
      "model": "deepseek-flash",
      "access": "API api.deepseek.com",
      "max_tokens": 384000,
      "answer": "answers/dsflash.json",
      "grade": "grades/dsflash.txt",
      "solution": "solutions/dsflash/solution.mjs",
      "verdict": "164 сцены из 164 и все три замера скорости, и снова самый быстрый ответ среди безошибочных: 3,5 минуты. На рассуждение ушло почти 39 тысяч токенов, код 335 строк."
    },
    {
      "id": "opusmax",
      "name": "Claude Opus 5.5 (effort max)",
      "vendor": "Anthropic",
      "model": "claude-opus-5-5",
      "access": "партнёрский шлюз, нативный `/messages`, `thinking: adaptive`, `effort: max`",
      "max_tokens": 128000,
      "answer": "answers/opusmax.json",
      "grade": "grades/opusmax.txt",
      "solution": "solutions/opusmax/solution.mjs",
      "verdict": "158 сцен из 164 и все три замера скорости, ответ за 30 секунд без размышления. В трёх случайных сценах не совпали мировые матрицы: модель один раз обновляет матрицы и потом применяет все `lookAt` подряд, поэтому потомок поворачивается по устаревшему положению родителя, у которого тоже есть `lookAt`. Ещё три промаха на проверке ввода: не ловятся неверный цвет, цвет из четырёх цифр и неверный порядок поворота у узла без `rotation`. Отдельная проверка показала, что размышление отключает последняя фраза задания «Ответь ТОЛЬКО кодом»: с фразой «сначала продумай» тот же Opus думал 6 тысяч токенов и прошёл 161 сцену."
    }
  ],
  "findings": [
    [
      "Пять моделей прошли всё.",
      "Opus 5.5 агентом, Qwen3.8-Max, Kimi K3.1 Pro, GPT-6.1 Sol и DeepSeek Flash прошли 164 сцены из 164: совпали матрицы, габариты, цвета в линейном пространстве, матрицы экземпляров и все 63 луча из камеры. Ловушки three.js вроде `lookAt`, который у объекта и у камеры смотрит в разные стороны, никого не поймали."
    ],
    [
      "Фраза в задании выключила размышление у Opus через API.",
      "«Ответь ТОЛЬКО кодом» адаптивный Opus 5.5 понимает как «не размышляй», даже при `effort: max`, и пишет код с 5-й секунды. Проверка шлюза показала, что `effort` передаётся правильно. С формулировкой «сначала продумай» Opus думал 6 тысяч токенов и прошёл 161 сцену вместо 158. В следующих тестах формулировка заменена."
    ],
    [
      "Скорость кода здесь не различает модели.",
      "Все решения строят 50 000 экземпляров и тысячи объектов с `lookAt` за сотые доли секунды. Места среди безошибочных определяются суммарным временем замеров, а эта разница на уровне погрешности."
    ],
    [
      "Время ответа различается почти в 70 раз.",
      "Opus через API ответил за 30 секунд, Opus-агент за 2 минуты 40 секунд, DeepSeek Flash за 3,5 минуты, GPT за 5 минут, Kimi за 12 минут, Qwen за 34 минуты. Колонка «Токенов/с» в таблице показывает, кто медленно пишет, а кто много думает."
    ]
  ],
  "files": [
    [
      "README.md",
      "отчёт в формате Markdown"
    ],
    [
      "report.html",
      "страница отчёта с графиками и галереей"
    ],
    [
      "bench.json",
      "метаданные: участники, условия, нюансы и выводы, из них собирается отчёт"
    ],
    [
      "task/task.md",
      "задание, которое получили модели"
    ],
    [
      "harness/runner.mjs",
      "скрытые тесты на Node: сцены, генератор, сравнение с эталоном, лучи"
    ],
    [
      "harness/reference.mjs",
      "эталонная сборка сцены"
    ],
    [
      "harness/test_three.py",
      "обёртка стенда и рендер галереи в Chrome"
    ],
    [
      "gallery/",
      "контрольная сцена в исполнении каждой модели и карты отличий"
    ],
    [
      "answers/<id>.json",
      "метаданные ответа: время и токены"
    ],
    [
      "solutions/<id>/solution.mjs",
      "код, который написала модель"
    ],
    [
      "grades/<id>.txt",
      "результаты тестов и список падений"
    ]
  ]
}
