Розробка метавсесвіту (Metaverse)

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Розробка метавсесвіту (Metaverse)
Складний
від 2 тижнів до 3 місяців
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1285
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1198
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    902
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1120
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    588
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    855

Розробка метавселенної

Метавселенна—перевантажений термін. Перед проектуванням виберіть конкретну модель: це постійний 3D світ із взаємодією гравців у реальному часі (як Decentraland, The Sandbox), чи соціальний шар над різними додатками, чи віртуальні офіси для enterprise? Кожна модель—різний технологічний стек.

Я опишу архітектуру web3-native постійного світу: багатокористувацьке 3D середовище з NFT власністю земель/активів, on-chain економікою та децентралізованим управлінням. Найбільш технічно складний і найцікавіший варіант.

Архітектурні шари метавселенної

1. Шар блокчейну: власність та економіка

Усе цінне існує в блокчейні:

  • LAND NFT—ділянки віртуальної землі (ERC-721)
  • Avatar NFT—персонажи з атрибутами
  • Wearables NFT—одяг, предмети (ERC-1155 для fungible, ERC-721 для унікальних)
  • Токен управління—участь в DAO управління
  • In-world валюта—ERC-20 токен для економіки

Усе іншe—off-chain (контент земельних ділянок, 3D активи, історія взаємодій).

2. Шар контенту: що розташовується на LAND

Власник LAND розміщує на ділянці контент: 3D сцени (файли GLTF/GLB), скрипти інтерактивності, портали в інші світи. Контент зберігається децентралізовано—IPFS або Arweave.

3. Real-time шар: багатокористувацький рушій

Гравці бачать один одного та взаємодіють у реальному часі—це завдання real-time мережі, а не блокчейну. Ігрові сервери (або P2P peer relay) синхронізують позиції та стани аватарів.

4. Шар додатків: dApps та ігри на LAND

Власник землі розміщує додатки—міні-ігри, галереї NFT, віртуальні магазини, концертні майданчики. Кожен додаток може мати власну on-chain логіку.

Система LAND: NFT земля та координатна сітка

Координатна система

Класичний підхід: карта як 2D координатна сітка. Decentraland використовує (-150, -150) до (150, 150). The Sandbox—408×408.

contract LandRegistry is ERC721 {
    int16 public constant MIN_X = -100;
    int16 public constant MAX_X = 100;
    int16 public constant MIN_Y = -100;
    int16 public constant MAX_Y = 100;
    
    // Token ID кодує координати: id = (x + 100) * 201 + (y + 100)
    function coordinatesToId(int16 x, int16 y) public pure returns (uint256) {
        require(x >= MIN_X && x <= MAX_X, "X out of range");
        require(y >= MIN_Y && y <= MAX_Y, "Y out of range");
        return uint256(uint16(x - MIN_X)) * 201 + uint256(uint16(y - MIN_Y));
    }
    
    function idToCoordinates(uint256 tokenId) public pure returns (int16 x, int16 y) {
        y = int16(int256(tokenId % 201)) + MIN_Y;
        x = int16(int256(tokenId / 201)) + MIN_X;
    }
    
    // Перевірка сусідства: потрібна для Estate (об'єднання суміжних ділянок)
    function isAdjacent(uint256 tokenId1, uint256 tokenId2) public pure returns (bool) {
        (int16 x1, int16 y1) = idToCoordinates(tokenId1);
        (int16 x2, int16 y2) = idToCoordinates(tokenId2);
        int16 dx = x1 - x2;
        int16 dy = y1 - y2;
        return (dx == 0 && (dy == 1 || dy == -1)) || (dy == 0 && (dx == 1 || dx == -1));
    }
}

Estate: об'єднання суміжних LAND

Власник кількох суміжних ділянок може об'єднати їх в Estate для побудови більших сцен:

contract EstateRegistry is ERC721 {
    struct Estate {
        uint256[] landIds;   // включені LAND токени
        string name;
        string ipfsHash;     // метаданні
    }
    
    mapping(uint256 => Estate) public estates;
    
    function createEstate(
        uint256[] calldata landIds,
        string calldata name
    ) external returns (uint256 estateId) {
        require(landIds.length >= 2, "Need at least 2 parcels");
        
        // Перевіримо власність та сусідство
        for (uint256 i = 0; i < landIds.length; i++) {
            require(landRegistry.ownerOf(landIds[i]) == msg.sender, "Not land owner");
        }
        require(_isConnectedGraph(landIds), "Parcels not adjacent");
        
        // Перенесемо LAND до контракту estate (заблокувати)
        for (uint256 i = 0; i < landIds.length; i++) {
            landRegistry.transferFrom(msg.sender, address(this), landIds[i]);
        }
        
        estateId = ++nextEstateId;
        estates[estateId] = Estate({ landIds: landIds, name: name, ipfsHash: "" });
        _mint(msg.sender, estateId);
        
        emit EstateCreated(estateId, msg.sender, landIds);
    }
    
    // BFS перевірка, що всі ділянки пов'язані в один граф
    function _isConnectedGraph(uint256[] calldata ids) internal view returns (bool) {
        if (ids.length == 1) return true;
        
        bool[] memory visited = new bool[](ids.length);
        uint256[] memory queue = new uint256[](ids.length);
        uint256 qHead = 0;
        uint256 qTail = 0;
        
        visited[0] = true;
        queue[qTail++] = ids[0];
        
        while (qHead < qTail) {
            uint256 current = queue[qHead++];
            for (uint256 i = 0; i < ids.length; i++) {
                if (!visited[i] && landRegistry.isAdjacent(current, ids[i])) {
                    visited[i] = true;
                    queue[qTail++] = ids[i];
                }
            }
        }
        
        for (uint256 i = 0; i < ids.length; i++) {
            if (!visited[i]) return false;
        }
        return true;
    }
}

Система контенту: що розміщується на LAND

Дескриптор сцени

Кожен LAND має сцену—набір 3D об'єктів, скриптів, порталів. Зберігається на IPFS:

// Дескриптор сцени (IPFS JSON)
interface SceneDescriptor {
  version: '2.0';
  landId: number;
  owner: string;           // ethereum адреса
  title: string;
  description: string;
  
  // 3D контент
  models: Array<{
    src: string;           // ipfs://Qm... посилання на GLTF/GLB
    position: [number, number, number];
    rotation: [number, number, number];
    scale: [number, number, number];
  }>;
  
  // Скрипти інтерактивності
  scripts: Array<{
    src: string;           // ipfs://Qm... модуль JavaScript
    entryPoint: string;    // ім'я експортованої функції
  }>;
  
  // Точки входу для аватарів
  spawnPoints: Array<{
    position: [number, number, number];
    cameraTarget: [number, number, number];
  }>;
  
  // Посилання на суміжні землі / портали
  portals: Array<{
    position: [number, number, number];
    targetLandId: number;
    targetUrl?: string;    // або зовнішня URL
  }>;
}

Публікування сцени:

contract LandContent {
    // IPFS хеш сцени для кожної LAND
    mapping(uint256 => string) public sceneHash;
    mapping(uint256 => uint256) public sceneVersion;
    
    function publishScene(uint256 landId, string calldata ipfsHash) external {
        require(landRegistry.ownerOf(landId) == msg.sender, "Not owner");
        
        // Базова валідація: непустий хеш
        require(bytes(ipfsHash).length == 46, "Invalid IPFS hash"); // Qm... = 46 символів
        
        sceneHash[landId] = ipfsHash;
        sceneVersion[landId]++;
        
        emit ScenePublished(landId, msg.sender, ipfsHash, sceneVersion[landId]);
    }
}

SDK сценарії сцени

Розробники пишуть скрипти для інтерактивності на LAND. Децентралізована версія Unity/Unreal сценаріїв:

// SDK сценарій сцени метавселенної (виконується в sandbox iframe/WebWorker)
import { engine, Transform, MeshRenderer, OnPointerDown } from '@metaverse/sdk';

// Інтерактивні двері
const door = engine.addEntity();
engine.addComponentOrReplace(door, Transform, {
  position: { x: 0, y: 0, z: 5 },
  rotation: { x: 0, y: 0, z: 0, w: 1 },
  scale: { x: 1, y: 1, z: 1 },
});

let isOpen = false;

engine.addComponentOrReplace(door, OnPointerDown, {
  callback: async () => {
    isOpen = !isOpen;
    // Анімуємо відкриття/закриття
    const transform = engine.getComponent(door, Transform);
    transform.rotation = isOpen
      ? Quaternion.fromEulerDegrees(0, 90, 0)
      : Quaternion.fromEulerDegrees(0, 0, 0);
  },
  hoverText: isOpen ? 'Close door' : 'Open door',
});

// NFT гейт: тільки власники певного NFT можуть увійти
import { checkNFTOwnership } from '@metaverse/blockchain';

engine.addComponentOrReplace(nftGate, OnPointerDown, {
  callback: async () => {
    const userAddress = await engine.getUserAddress();
    const hasNFT = await checkNFTOwnership(userAddress, NFT_CONTRACT, TOKEN_ID);
    
    if (!hasNFT) {
      engine.showNotification('You need the Golden Pass NFT to enter');
      return;
    }
    
    engine.teleportPlayer({ x: INSIDE_X, y: 0, z: INSIDE_Z });
  },
});

Sandbox сценарія—ізольований WebWorker або iframe без прямого доступу до DOM. API взаємодії з блокчейном надається через postMessage, а не прямий доступ до гаманця.

Real-time мережа: синхронізація аватарів

Архітектура: Area Servers

Світ розділений на регіони (кожен регіон = N×N LAND). Кожен регіон обслуговується одним ігровим сервером. Коли гравець переходить між регіонами—передача іншому серверу.

                    ┌─────────────────────────────┐
                    │    Load Balancer / Router    │
                    │   (за координатами гравця)   │
                    └──────────┬──────────────────┘
                               │
          ┌────────────────────┼────────────────────┐
          ▼                    ▼                    ▼
  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐
  │  Area Server │    │  Area Server │    │  Area Server │
  │  Region A    │    │  Region B    │    │  Region C    │
  │  (-100,-100) │    │  (0,0)       │    │  (100,100)   │
  │  до (0,0)   │    │  до (100,100)│    │  ...         │
  └──────────────┘    └──────────────┘    └──────────────┘
// Area Server: керування аватарами в регіоні
import { WebSocketServer } from 'ws';
import { World } from '@dimforge/rapier3d'; // фізичний рушій

class AreaServer {
  private players = new Map<string, PlayerState>();
  private physicsWorld = new World({ x: 0, y: -9.81, z: 0 });
  
  handlePlayerJoin(playerId: string, ws: WebSocket, position: Vector3) {
    const state: PlayerState = {
      id: playerId,
      position,
      rotation: Quaternion.identity(),
      animation: 'idle',
      ws,
    };
    
    this.players.set(playerId, state);
    
    // Відправляємо новому гравцю стани всіх в регіоні
    const snapshot = this.getRegionSnapshot();
    ws.send(JSON.stringify({ type: 'region_snapshot', players: snapshot }));
    
    // Повідомляємо інших про нового гравця
    this.broadcast({ type: 'player_joined', player: state }, playerId);
  }
  
  handleMovement(playerId: string, movement: MovementPacket) {
    const player = this.players.get(playerId);
    if (!player) return;
    
    // Серверна валідація руху (anti-cheat)
    if (!this.isValidMovement(player, movement)) {
      // Коригуємо позицію
      player.ws.send(JSON.stringify({
        type: 'position_correction',
        position: player.position,
      }));
      return;
    }
    
    player.position = movement.position;
    player.rotation = movement.rotation;
    player.animation = movement.animation;
    
    // Broadcast всім в регіоні (delta compression)
    this.broadcastMovement(playerId, movement);
  }
  
  // 20 оновлень/сек для плавного руху
  private startTickLoop() {
    setInterval(() => this.tick(), 50);
  }
  
  private tick() {
    this.physicsWorld.step();
    
    // Збираємо dirty states та надсилаємо батчем
    const updates = this.getDirtyPlayerStates();
    if (updates.length > 0) {
      this.broadcast({ type: 'batch_update', updates });
    }
  }
}

Proximity-based Broadcasting

Не потрібно надсилати позицію гравця всім в регіоні—тільки тим, хто рядом. Interest Management:

const VISIBILITY_RADIUS = 100; // метри

function getVisiblePlayers(playerId: string): string[] {
  const player = players.get(playerId)!;
  return Array.from(players.values())
    .filter(p => p.id !== playerId)
    .filter(p => distance(p.position, player.position) < VISIBILITY_RADIUS)
    .map(p => p.id);
}

Це зменшує пропускну здатність з O(N²) до O(N × K), де K = середня кількість видимих гравців.

In-world економіка

Контракт Marketplace

Власник LAND продає віртуальні товари всередину світу:

contract InWorldMarketplace {
    struct Listing {
        address seller;
        address nftContract;
        uint256 tokenId;
        uint256 price;          // в in-world валюті (ERC-20)
        uint256 landId;         // на якій LAND виставлений товар
        bool active;
    }
    
    // Royalty для власника LAND: 2.5% від продажів на його землі
    uint256 public constant LAND_ROYALTY = 250; // basis points
    
    function buy(uint256 listingId) external {
        Listing storage listing = listings[listingId];
        require(listing.active, "Not active");
        
        uint256 landRoyalty = listing.price * LAND_ROYALTY / 10_000;
        uint256 sellerProceeds = listing.price - landRoyalty;
        
        // Покупець платить in-world валютою
        worldToken.transferFrom(msg.sender, listing.seller, sellerProceeds);
        worldToken.transferFrom(msg.sender, landRegistry.ownerOf(listing.landId), landRoyalty);
        
        // Передаємо NFT
        IERC721(listing.nftContract).transferFrom(
            address(this), msg.sender, listing.tokenId
        );
        
        listing.active = false;
        emit Sale(listingId, msg.sender, listing.price);
    }
}

Play-to-Earn механіки

In-world активності можуть генерувати in-world валюту:

  • Відвідування подій на LAND (check-in reward)
  • Виконання квестів, створених власниками LAND
  • Участь у міні-іграх

Важливо: темп выпуску має бути контрольованим для запобігання інфляції. Рекомендація: тижневий ліміт видачі + механізм halving як у Bitcoin.

DAO та управління

// Управління через Compound-style голосування
contract MetaverseDAO is Governor, GovernorTimelockControl {
    // Тримання LAND дає право голосу
    function _getVotes(
        address account,
        uint256 blockNumber,
        bytes memory
    ) internal view override returns (uint256) {
        // 1 LAND = 1 голос + бонус за staking токена управління
        uint256 landVotes = landRegistry.balanceOf(account); // на blockNumber
        uint256 tokenVotes = govToken.getPastVotes(account, blockNumber);
        return landVotes + tokenVotes;
    }
}

Управління вирішує: розмір світу (нові LAND), параметри економіки, whitelist форматів контенту, оновлення контрактів.

Технологічний стек

3D рендеринг

Three.js + React Three Fiber—для web-native метавселенної. Хороша підтримка GLTF, PBR матеріали, оптимізація продуктивності через instancing та LOD.

Babylon.js—альтернатива, особливо добра з WebXR (VR/AR). Decentraland використовує Babylon.js.

Unity WebGL—найкращої якості графіка, але великий bundle (50–200 MB), повільне завантаження. Добре для desktop-орієнтованого продукту.

Повний стек

Шар Технологія
Blockchain Polygon PoS або Arbitrum (низький газ для LAND транзакцій)
LAND/NFT Solidity ERC-721 + ERC-1155, Foundry
Управління OpenZeppelin Governor + TimelockController
Зберігання IPFS (Pinata/Web3.Storage) + Arweave для постійного контенту
Real-time Node.js + uWebSockets.js (висока продуктивність)
Фізика Rapier3D (Rust/WASM, швидше за Cannon.js)
3D Web Three.js + React Three Fiber + Drei
Система аватарів ReadyPlayerMe SDK або користувацькі VRM аватари
Стан Redis для стану регіону, PostgreSQL для постійних даних
Індексування The Graph (события LAND transfers, scene updates)

Етапи розробки

Фаза Вміст Сроки
Foundation Контракти LAND, координатна система, базовий marketplace 4–6 тиж
Content system Дескриптор сцени, IPFS зберігання, публікування сцени 3–4 тиж
3D Client Three.js світ, завантаження сцени, базова навігація 6–8 тиж
Real-time Area servers, синхронізація аватарів, proximity система 6–8 тиж
Economy In-world токен, marketplace, play-to-earn 4–6 тиж
Scripting SDK Sandbox сценаріїв сцени, NFT gate APIs 4–6 тиж
Governance Контракти DAO, UI голосування 3–4 тиж
Audit LAND, marketplace, economy контракти 5–8 тиж
Alpha launch Приватна альфа з обмеженою картою 2–4 тиж

Реалістичний сроки від нуля до public alpha: 12–18 місяців для команди 8–12 людей (2–3 blockchain, 2–3 3D/frontend, 2 backend, 1 PM, 1 designer). Один з найбільш scope-складних проектів у Web3.

Головний ризик не технічний, а продуктовий: без контенту на LAND та активної спільноти світ буде пустим. Паралельно з розробкою потрібна програма для ранніх власників LAND та контент-творців.