К основному содержанию
правило

three-js — правило для Cursor: стандарты кода three.js

Правило для Cursor задаёт стандарты разработки на three.js: обработка ошибок WebGL, ленивая загрузка ассетов, оптимизация цикла рендера и освобождение ресурсов.

Установить в Cursor · Вручную: положить файлы Все способы и платформы ↓
.cursor/rules/three-js.mdc
Открыть на GitHub

Что делает three-js

Правило подключается к файлам **/*.{js,jsx} и описывает пять блоков практик. Первый — работа с WebGL: проверять gl.getError() во время разработки, а в продакшене убрать блокирующие вызовы вроде getError() и getParameter(), заранее спрашивать поддержку расширений через gl.getExtension() и держать запасной путь. Второй — загрузка ассетов: GLTFLoader и TextureLoader вызываются только тогда, когда модель вот-вот появится в кадре, файлы лежат в public/.

Дальше про производительность и память. Для повторяющихся объектов правило советует InstancedMesh и общие материалы вместо тысячи отдельных мешей, а текстуры — собирать в атласы. При удалении объекта со сцены нужно вручную вызвать dispose() у геометрии, материалов и текстур: сборщик мусора чистит только ссылки в JS, видеопамять он не трогает. Есть отдельная функция-пример disposeObject, которая обходит материал-массив и снимает объект с родителя.

Последний блок — структура проекта: npm для зависимостей, Vite для сборки, точка входа main.js и модульные импорты из three/addons/. Файл кладётся в .cursor/rules/three-js.mdc. Если в проекте three.js не используется, правило будет только шуметь в подсказках — это повод проверить, стоит ли его вообще подключать.

Какие задачи решает

  • поймать ошибки WebGL, которые иначе проходят молча
  • не уронить сцену на железе без нужного расширения
  • убрать фризы при загрузке тяжёлых моделей и текстур
  • сократить число draw calls на повторяющихся объектах
  • освободить видеопамять при удалении объекта со сцены

Примеры запросов агенту

  • добавь InstancedMesh вместо тысячи отдельных мешей в этой сцене
  • проверь поддержку расширения перед использованием InstancedMesh
  • напиши dispose для этого меша: геометрия, материал, текстура

Как установить three-js

Вручную: положить файлы

.cursor/rules/three-js.mdc

Во frontmatter: description, globs, alwaysApply

По шагам, с командами для каждой платформы: Cursor rules: файлы .mdc, четыре режима и замена .cursorrules

Вопросы о three-js

Как установить three-js в Cursor?

Создайте файл .cursor/rules/three-js.mdc в корне проекта и вставьте в него содержимое правила.

Что делает правило three-js?

Задаёт стандарты для кода на three.js: проверка ошибок WebGL и поддержки расширений, ленивая загрузка ассетов, инстансинг, освобождение ресурсов через dispose() и структура проекта на npm с Vite.

К каким файлам применяется правило?

Glob-маска **/*.{js,jsx} — правило подхватывается в JavaScript и JSX файлах проекта.

Исходный текст

three-js.mdc · CC0-1.0
---
description: Enforce modern, performant, and maintainable three-js development practices, focusing on WebGL error handling, efficient asset management, and render loop optimization.
globs: **/*.{js,jsx}
---
# three-js Best Practices

This guide establishes the definitive coding standards for three-js development, ensuring robust, performant, and maintainable 3D applications. Adhere to these rules to prevent common pitfalls and leverage three-js effectively.

## 1. WebGL Error Handling & Extension Support

Always treat WebGL as a low-level layer requiring explicit error checks. Never assume universal extension support.

### ✅ GOOD: Proactive Error Checking & Graceful Fallbacks

During development, actively check `gl.getError()` to catch issues beyond `OUT_OF_MEMORY` or `CONTEXT_LOST`. In production, avoid blocking calls like `getError()` and `getParameter()`. Query extension support and provide fallbacks.

```javascript
// Development-only error checking (e.g., in a debug utility)
function checkGLErrors(gl) {
  let error = gl.getError();
  while (error !== gl.NO_ERROR) {
    console.error(`WebGL Error: ${error}`);
    error = gl.getError();
  }
}

// Extension support check
const renderer = new THREE.WebGLRenderer();
const gl = renderer.getContext();

if (gl.getExtension('ANGLE_instanced_arrays')) {
  // Use instanced rendering
} else {
  console.warn('ANGLE_instanced_arrays not supported, falling back to non-instanced rendering.');
  // Implement fallback or disable feature
}
```

### ❌ BAD: Ignoring WebGL Errors & Blindly Using Extensions

```javascript
// No error checking, leading to silent failures
const geometry = new THREE.BufferGeometry();
// ... potentially invalid buffer setup ...
renderer.render(scene, camera); // Errors might occur but go unnoticed

// Using advanced features without checking support
const instancedMesh = new THREE.InstancedMesh(geometry, material, count); // Fails on unsupported hardware
```

## 2. Asset Management & Lazy Loading

Optimize initial load times and prevent frame stalls by loading large assets lazily and using the correct loaders.

### ✅ GOOD: Lazy Loading with Dedicated Loaders & Modular Structure

Load assets only when needed. Use `GLTFLoader`, `TextureLoader`, etc., and organize assets in a `public/` directory.

```javascript
// main.js
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

export function loadModel(url, scene) {
  const loader = new GLTFLoader();
  return new Promise((resolve, reject) => {
    loader.load(
      url,
      (gltf) => {
        scene.add(gltf.scene);
        resolve(gltf.scene);
      },
      (xhr) => {
        console.log(`${(xhr.loaded / xhr.total) * 100}% loaded`);
      },
      (error) => {
        console.error('An error happened loading the model:', error);
        reject(error);
      }
    );
  });
}

// In your scene setup, call loadModel when the asset is about to be visible
// await loadModel('/public/models/my-asset.glb', scene);
```

### ❌ BAD: Synchronous Loading & Unorganized Assets

```javascript
// main.js - synchronous loading blocks the main thread
// This is a simplified example, actual synchronous loading is less common with modern loaders
// but conceptually, loading all assets at once without a loading screen is bad.
const texture = new THREE.TextureLoader().load('large_texture.jpg'); // Blocks until loaded
const model = new GLTFLoader().load('heavy_model.glb'); // Blocks until loaded
scene.add(model.scene);
// ... UI freezes ...
```

## 3. Performance Optimization

Minimize draw calls, reuse resources, and keep shaders efficient.

### ✅ GOOD: Instancing, Geometry Batching, Material Reuse, & Texture Atlases

For repetitive objects, use `InstancedMesh`. Combine static geometries where possible. Reuse materials across objects. Consolidate textures into atlases.

```javascript
// InstancedMesh for many identical objects
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshNormalMaterial();
const count = 1000;
const mesh = new THREE.InstancedMesh(geometry, material, count);

const matrix = new THREE.Matrix4();
for (let i = 0; i < count; i++) {
  matrix.setPosition(Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50);
  mesh.setMatrixAt(i, matrix);
}
mesh.instanceMatrix.needsUpdate = true;
scene.add(mesh);

// Material Reuse
const sharedMaterial = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const obj1 = new THREE.Mesh(new THREE.BoxGeometry(), sharedMaterial);
const obj2 = new THREE.Mesh(new THREE.SphereGeometry(), sharedMaterial);
```

### ❌ BAD: Excessive Draw Calls & Unique Materials

```javascript
// Creating individual meshes for many identical objects
for (let i = 0; i < 1000; i++) {
  const geometry = new THREE.BoxGeometry(1, 1, 1);
  const material = new THREE.MeshNormalMaterial(); // New material for each
  const mesh = new THREE.Mesh(geometry, material);
  mesh.position.set(Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50);
  scene.add(mesh); // 1000 draw calls, 1000 materials
}
```

## 4. Resource Disposal

Prevent memory leaks by explicitly disposing of three-js objects when they are no longer needed.

### ✅ GOOD: Explicit Disposal

Always call `dispose()` on geometries, materials, textures, and render targets when removing them from the scene.

```javascript
function disposeObject(obj) {
  if (obj.geometry) {
    obj.geometry.dispose();
  }
  if (obj.material) {
    if (Array.isArray(obj.material)) {
      obj.material.forEach(material => material.dispose());
    } else {
      obj.material.dispose();
    }
  }
  if (obj.texture) { // For textures directly attached to objects
    obj.texture.dispose();
  }
  if (obj.parent) {
    obj.parent.remove(obj);
  }
}

// Example usage:
const meshToRemove = scene.getObjectByName('myDynamicMesh');
if (meshToRemove) {
  disposeObject(meshToRemove);
}
```

### ❌ BAD: Relying on Garbage Collection

```javascript
const mesh = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial());
scene.add(mesh);
// Later, just remove from scene without disposing resources
scene.remove(mesh); // Geometry and material still consume GPU memory
mesh = null; // Only JS reference is cleared, not GPU resources
```

## 5. Project Structure & Development Workflow

Adopt a modern development setup for efficient development and deployment.

### ✅ GOOD: npm + Vite & Modular Imports

Use npm for dependency management and Vite for local development and production builds. Structure your project with a clear entry point (`main.js`) and a `public/` folder for static assets.

```javascript
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>My three.js App</title>
</head>
<body>
    <script type="module" src="/main.js"></script>
</body>
</html>

// main.js
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// ... rest of your scene setup
```

### ❌ BAD: CDN-only & Global Scope Pollution

```html
<!-- index.html -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/controls/OrbitControls.js"></script>
<script>
    // All code in global scope, no module benefits
    const scene = new THREE.Scene();
    // ...
</script>
```

© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc

Похожие правила IDE

Всё по теме «Геймдев и 3D: Unity, Unreal, Godot, Blender» →
react-three-fiber freshtechbro Скилл обучает агента строить декларативные 3D-сцены в React через Three.js, настраивать хуки рендера и загружать модели через Suspense. CX Codex +1 3 800установок three-best-practices three-agent-skills Скилл с набором правил по Three.js: подсказывает агенту, как не течь по памяти и держать кадры. Пригодится, когда пишете или чините 3D-сцену. CX Codex +1 1 500установок webgl-3d-object MengTo Добавляет в агент правила генерации трёхмерных объектов на Three.js с честным PBR-освещением, тенями и анимацией вместо псевдо-3D на CSS. CX Codex +1 1 600установок threejs-react-three-fiber CloudAI-X Скилл для тех, кто пишет three.js-сцены компонентами React. Подсказывает, как устроены Canvas, хуки и события указателя в React Three Fiber. CX Codex +1 1 300установок three-webgl-game официальный OpenAI Помогает создавать браузерные 3D-игры на чистом Three.js, TypeScript и Vite с физикой Rapier и управлением игровым циклом без React. CX Codex GP ChatGPT 48установок threejs-geometry CloudAI-X Скилл учит ИИ-агента создавать стандартные и процедурные геометрии three.js, настраивать буферные атрибуты и генерировать 3D-текст. CX Codex +1 14 600установок

Из того же набора69

vercel Правило для Cursor с набором рекомендаций по разработке и деплою приложений на Vercel. Пригодится, если агент пишет код для Next.js и вы хотите, чтобы он сразу держал в голове конвенции платформы. ★ 3 579звёзд репо unittest Правило задаёт агенту стандарт оформления тестов на unittest: структура каталогов, имена классов и методов, ассерты, моки. ★ 3 579звёзд репо transformers Правило для Cursor задаёт стиль работы с библиотекой 🤗 Transformers: модульные модели, типизация, Trainer вместо ручных циклов обучения. ★ 3 579звёзд репо tornado Правило для Cursor задаёт стиль кода в Tornado: только async/await для ввода-вывода, полные аннотации типов и один обработчик ошибок на всё приложение. ★ 3 579звёзд репо svelte Правило для Cursor задаёт, как писать компоненты Svelte 5: руны вместо старой реактивности, типизация и ключи в списках. Пригодится, если проект уже на Svelte 5. ★ 3 579звёзд репо streamlit Правило для Cursor задаёт, как писать приложения на Streamlit: кэшировать тяжёлые операции, держать UI отдельно от логики и разбивать проект на модули. ★ 3 579звёзд репо sqlalchemy Правило для Cursor задаёт стиль SQLAlchemy 2.x: типизированные модели, сессии через контекстный менеджер, select() вместо устаревшего Query. ★ 3 579звёзд репо solidity Правило задаёт стиль и требования к Solidity-коду: фиксированный pragma, кастомные ошибки, защита от реентрантности. Пригодится, когда пишете контракты в Cursor. ★ 3 579звёзд репо

Спонсоры проекта

Компании, которые помогают держать аналитику открытой