{"id":490652,"date":"2026-08-12T08:47:17","date_gmt":"2026-08-12T08:47:17","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=490652"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2026-08-12T08:47:17","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=490652","title":{"rendered":"\u041a\u0430\u043a \u044f \u0441\u043e\u0431\u0440\u0430\u043b \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0439 \u0445\u043e\u0440\u0440\u043e\u0440 \u043d\u0430 Three.js: GLB-\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442, \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0438 \u0438 PS1-\u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u043b\u0430\u0431\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440.<\/p>\n<p>\u042f frontend-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0438 \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e \u0441 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430\u043c\u0438. \u0412 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043c\u043e\u043c\u0435\u043d\u0442 \u043c\u043d\u0435 \u0441\u0442\u0430\u043b\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043c\u043e\u0436\u043d\u043e \u043b\u0438 \u043d\u0430 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u043e\u043c \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u0432\u0435\u0431-\u0441\u0442\u0435\u043a\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435 \u0434\u0435\u043c\u043e \u0441 \u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u043c\u0441\u044f \u043a\u0443\u0431\u043e\u043c, \u0430 \u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d\u043d\u0443\u044e 3D-\u0438\u0433\u0440\u0443 \u2014 \u0441 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u043e\u0439 \u0441\u0446\u0435\u043d\u044b, \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c, \u0437\u0432\u0443\u043a\u043e\u043c, \u043c\u0435\u043d\u044e, \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0435\u0439 \u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0435\u0439 \u043d\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435.<\/p>\n<p>\u0422\u0430\u043a \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c Taproom 8 \u2014 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u0430\u044f \u0438\u0433\u0440\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043a\u0430\u0442\u044c \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0438 \u0432 \u043c\u0440\u0430\u0447\u043d\u043e\u043c \u0431\u0430\u0440\u0435.<\/p>\n<p>\u0418\u0433\u0440\u0430\u0442\u044c: <a href=\"https:\/\/yandex.ru\/games\/app\/taproom-8-555243\" rel=\"noopener noreferrer nofollow\">Taproom 8 \u0432 \u042f\u043d\u0434\u0435\u043a\u0441 \u0418\u0433\u0440\u0430\u0445<\/a><\/p>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434: <a href=\"https:\/\/github.com\/StaburovAlexey\/Taproom8-anomaly\" rel=\"noopener noreferrer nofollow\">GitHub<\/a><\/p>\n<p>\u041d\u0438\u0436\u0435 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043d\u0435 \u0441\u0442\u043e\u043b\u044c\u043a\u043e \u043e \u0441\u0430\u043c\u043e\u0439 \u0438\u0433\u0440\u0435, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043e\u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0432\u043d\u0443\u0442\u0440\u0438.<\/p>\n<h3>\u0421 \u0447\u0435\u0433\u043e \u0432\u0441\u0451 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c<\/h3>\n<p>\u0421 Three.js \u044f \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043b\u0441\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 2D\/3D-\u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430. \u0422\u0430\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0431\u044b\u043b\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438 \u043d\u0430 \u0441\u0446\u0435\u043d\u0435: \u043a\u0430\u043c\u0435\u0440\u043e\u0439, \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0435\u0439, \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430\u043c\u0438 \u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u043c\u0438.<\/p>\n<p>\u0412 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043c\u043e\u043c\u0435\u043d\u0442 \u044f \u043f\u043e\u0439\u043c\u0430\u043b \u0441\u0435\u0431\u044f \u043d\u0430 \u043c\u044b\u0441\u043b\u0438: \u0435\u0441\u043b\u0438 \u044f \u0443\u0436\u0435 \u0443\u043c\u0435\u044e \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u0438, \u0434\u0432\u0438\u0433\u0430\u0442\u044c \u043a\u0430\u043c\u0435\u0440\u0443 \u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043f\u043e\u0447\u0435\u043c\u0443 \u0431\u044b \u043d\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u043f\u043e\u0432\u0435\u0440\u0445 \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0438\u0433\u0440\u0443?<\/p>\n<p>\u0418\u0434\u0435\u044f \u0434\u043b\u044f Taproom 8 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430\u0441\u044c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0439. \u0418\u0433\u0440\u043e\u043a \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u0432 \u043a\u043e\u043c\u043d\u0430\u0442\u0443 \u0438 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u0438\u0434\u0438\u0442 \u0435\u0451 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435. \u042d\u0442\u043e \u043d\u0443\u043b\u0435\u0432\u043e\u0439 \u0446\u0438\u043a\u043b, \u0432 \u043d\u0451\u043c \u043d\u0435\u0442 \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0439. \u041d\u0443\u0436\u043d\u043e \u0437\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c \u043f\u043e\u043c\u0435\u0449\u0435\u043d\u0438\u0435, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0446\u0438\u043a\u043b\u044b. \u0412 \u043a\u0430\u0436\u0434\u043e\u043c \u0438\u0437 \u043d\u0438\u0445 \u043c\u043e\u0436\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c\u0441\u044f \u043e\u0434\u0438\u043d \u043e\u0431\u044a\u0435\u043a\u0442: \u0438\u0441\u0447\u0435\u0437\u043d\u0443\u0442\u044c \u0441\u0442\u0443\u043b, \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u0430, \u043f\u043e\u044f\u0432\u0438\u0442\u044c\u0441\u044f \u0441\u0442\u0440\u0430\u043d\u043d\u044b\u0439 \u0441\u0438\u043b\u0443\u044d\u0442 \u0438\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c\u0441\u044f \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0434\u0432\u0435\u0440\u0438.<\/p>\n<p>\u0418\u0433\u0440\u043e\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043e\u0434\u043d\u0443 \u0438\u0437 \u0434\u0432\u0443\u0445 \u0434\u0432\u0435\u0440\u0435\u0439:<\/p>\n<ul>\n<li>\n<p>\u00ab\u0415\u0441\u0442\u044c \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u044f\u00bb;<\/p>\n<\/li>\n<li>\n<p>\u00ab\u0410\u043d\u043e\u043c\u0430\u043b\u0438\u0439 \u043d\u0435\u0442\u00bb.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u043e\u0442\u0432\u0435\u0442 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u0442 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c, \u043e\u0448\u0438\u0431\u043a\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u043a \u043d\u0430\u0447\u0430\u043b\u0443.<\/p>\n<p>\u041d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0430 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0430\u044f. \u041d\u043e \u0432\u043e\u043a\u0440\u0443\u0433 \u043d\u0435\u0451 \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u043e\u044f\u0432\u0438\u043b\u0438\u0441\u044c \u0437\u0430\u0434\u0430\u0447\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435 \u0431\u044b\u043b\u043e \u0432 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u0435:<\/p>\n<ul>\n<li>\n<p>\u043a\u0430\u043a \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0440\u0430\u0443\u043d\u0434\u0430;<\/p>\n<\/li>\n<li>\n<p>\u043a\u0430\u043a \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0438 \u0431\u0435\u0437 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u044f \u0438\u0433\u0440\u043e\u0432\u043e\u0433\u043e \u043a\u043e\u0434\u0430;<\/p>\n<\/li>\n<li>\n<p>\u043a\u0430\u043a \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043c\u0435\u0436\u0434\u0443 Vue \u0438 Three.js;<\/p>\n<\/li>\n<li>\n<p>\u043a\u0430\u043a \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0443\u044e GLB-\u0441\u0446\u0435\u043d\u0443;<\/p>\n<\/li>\n<li>\n<p>\u043a\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0442\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043f\u043e\u0434 PS1;<\/p>\n<\/li>\n<li>\n<p>\u043a\u0430\u043a \u043f\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u0432\u043a\u043b\u0430\u0434\u043a\u0438 \u0438 \u0440\u0435\u043a\u043b\u0430\u043c\u043d\u044b\u0435 \u043f\u0430\u0443\u0437\u044b;<\/p>\n<\/li>\n<li>\n<p>\u043a\u0430\u043a \u043d\u0435 \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0435\u043b\u0435\u0444\u043e\u043d \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u0432 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439 \u043e\u0431\u043e\u0433\u0440\u0435\u0432\u0430\u0442\u0435\u043b\u044c.<\/p>\n<\/li>\n<\/ul>\n<h3>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h3>\n<p>\u0421\u0442\u0435\u043a \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0442\u0430\u043a\u0438\u043c:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u0422\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0417\u043e\u043d\u0430 \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Vue 3<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043c\u0435\u043d\u044e, \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438, HUD, \u044d\u043a\u0440\u0430\u043d\u044b \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044b<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">TypeScript<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0438\u0433\u0440\u043e\u0432\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u044b \u043c\u0435\u0436\u0434\u0443 \u043f\u043e\u0434\u0441\u0438\u0441\u0442\u0435\u043c\u0430\u043c\u0438<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Three.js<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0441\u0446\u0435\u043d\u0430, \u043a\u0430\u043c\u0435\u0440\u0430, \u043c\u043e\u0434\u0435\u043b\u0438, \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u0438 WebGL-\u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Vite<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0441\u0431\u043e\u0440\u043a\u0430 \u0438 dev-\u0441\u0435\u0440\u0432\u0435\u0440<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Pinia<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">vue-i18n<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0440\u0443\u0441\u0441\u043a\u0438\u0439 \u0438 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u0439 \u044f\u0437\u044b\u043a\u0438<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Vitest<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0438 \u0430\u0434\u0430\u043f\u0442\u0435\u0440\u043e\u0432<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u2014 \u043d\u0435 \u0441\u043c\u0435\u0448\u0438\u0432\u0430\u0442\u044c Vue-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0441 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438 3D-\u0441\u0446\u0435\u043d\u044b.<\/p>\n<p>\u0423\u0441\u043b\u043e\u0432\u043d\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u043e \u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u043e\u0451\u0432:<\/p>\n<pre><code>Vue UI  \u2193 typed EventBusGameCoordinator \/ LifecycleCoordinator  \u2193Game \u2192 SceneManager \u2192 GameScene  \u2193Three.js: camera, player, level, input, interaction, rendererPlatform adapters \u2192 Yandex Games SDK<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>Vue \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441 \u00ab\u043a\u0430\u043a\u043e\u0439 \u044d\u043a\u0440\u0430\u043d \u0441\u0435\u0439\u0447\u0430\u0441 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u00bb. \u0418\u0433\u0440\u043e\u0432\u043e\u0439 \u0441\u043b\u043e\u0439 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441 \u00ab\u0447\u0442\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0442\u0438 \u0432 \u043c\u0438\u0440\u0435\u00bb.<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u043d\u043e\u043f\u043a\u0430 \u0432 UI \u043d\u0435 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0434\u0432\u0435\u0440\u044c \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0438 \u043d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043c\u0435\u0442\u043e\u0434\u044b Three.js. \u041e\u043d\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0432\u044b\u0431\u043e\u0440\u0430 \u0434\u0432\u0435\u0440\u0438. <code>GameCoordinator<\/code> \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0435\u0433\u043e, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0440\u0430\u0443\u043d\u0434\u0430 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<h3>Three.js \u2014 \u044d\u0442\u043e \u043d\u0435 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0434\u0432\u0438\u0436\u043e\u043a<\/h3>\n<p>\u042d\u0442\u043e \u0432\u0430\u0436\u043d\u043e\u0435 \u0443\u0442\u043e\u0447\u043d\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u044f \u0441\u0430\u043c \u043e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0441\u043e\u0437\u043d\u0430\u043b \u0443\u0436\u0435 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<p>Three.js \u2014 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 3D-\u0433\u0440\u0430\u0444\u0438\u043a\u043e\u0439 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. \u041e\u043d\u0430 \u0434\u0430\u0451\u0442 \u0441\u0446\u0435\u043d\u0443, \u043a\u0430\u043c\u0435\u0440\u044b, \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u044e, \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b, \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b, \u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a\u0438 \u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0435\u0440. \u041d\u043e \u043e\u043d\u0430 \u043d\u0435 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0433\u043e\u0442\u043e\u0432\u0443\u044e \u0438\u0433\u0440\u043e\u0432\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u0443\u0440\u043e\u0432\u043d\u044f Unity \u0438\u043b\u0438 Unreal Engine.<\/p>\n<p>\u0412 Three.js \u043d\u0435\u0442 \u0433\u043e\u0442\u043e\u0432\u044b\u0445:<\/p>\n<ul>\n<li>\n<p>\u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u0441\u0446\u0435\u043d \u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u0432 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438;<\/p>\n<\/li>\n<li>\n<p>\u0438\u0433\u0440\u043e\u0432\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 \u0441 \u043d\u0443\u0436\u043d\u044b\u043c\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c\u0438;<\/p>\n<\/li>\n<li>\n<p>\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0439 \u0444\u0438\u0437\u0438\u043a\u0438 \u0438 \u043a\u043e\u043b\u043b\u0430\u0439\u0434\u0435\u0440\u043e\u0432;<\/p>\n<\/li>\n<li>\n<p>\u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0440\u0430\u0443\u043d\u0434\u043e\u0432 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0439;<\/p>\n<\/li>\n<li>\n<p>UI, \u043c\u0435\u043d\u044e \u0438 \u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439;<\/p>\n<\/li>\n<li>\n<p>\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u043e\u0439.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0441\u043b\u043e\u0439. \u042d\u0442\u043e \u043d\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 Unity. \u041f\u0440\u043e\u0441\u0442\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443\u0437\u043a\u0438\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432, \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0440\u0435\u0448\u0430\u0435\u0442 \u043e\u0434\u043d\u0443 \u0437\u0430\u0434\u0430\u0447\u0443:<\/p>\n<ul>\n<li>\n<p><code>Game<\/code> \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u043c \u0446\u0438\u043a\u043b\u043e\u043c \u0438\u0433\u0440\u044b;<\/p>\n<\/li>\n<li>\n<p><code>Loop<\/code> \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 <code>requestAnimationFrame<\/code>;<\/p>\n<\/li>\n<li>\n<p><code>SceneManager<\/code> \u0445\u0440\u0430\u043d\u0438\u0442 \u0430\u043a\u0442\u0438\u0432\u043d\u0443\u044e \u0441\u0446\u0435\u043d\u0443;<\/p>\n<\/li>\n<li>\n<p><code>GameScene<\/code> \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 \u0443\u0440\u043e\u0432\u0435\u043d\u044c, \u0438\u0433\u0440\u043e\u043a\u0430, \u0432\u0432\u043e\u0434, \u0437\u0432\u0443\u043a \u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f;<\/p>\n<\/li>\n<li>\n<p><code>Renderer<\/code> \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 WebGL \u0438 PS1-\u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d;<\/p>\n<\/li>\n<li>\n<p><code>GameCoordinator<\/code> \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u0435\u0441\u0441\u0438\u044f\u043c\u0438 \u0438 \u0440\u0430\u0443\u043d\u0434\u0430\u043c\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u0423 <code>Game<\/code> \u0435\u0441\u0442\u044c \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0446\u0438\u043a\u043b:<\/p>\n<pre><code>export class Game {  private readonly loop: Loop  public constructor(\/* ... *\/) {    this.loop = new Loop((deltaSeconds, elapsedSeconds) =&gt; {      this.update(deltaSeconds, elapsedSeconds)    })  }  private update(deltaSeconds: number, elapsedSeconds: number): void {    this.scenes.update(deltaSeconds, elapsedSeconds)    this.renderActiveScene()  }  private renderActiveScene(): void {    const scene = this.scenes.active    if (scene === null) {      return    }    this.renderer.render(scene.scene, scene.camera)  }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u043e\u0441\u0442\u043e, \u043d\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a\u043e\u0439 \u0441\u043b\u043e\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0435 \u0440\u0430\u0437\u043d\u043e\u0441\u0438\u0442\u044c \u0432\u044b\u0437\u043e\u0432\u044b <code>renderer.render<\/code>, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043f\u0430\u0443\u0437\u044b \u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0441\u0446\u0435\u043d \u043f\u043e Vue-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c.<\/p>\n<h3>\u0418\u0433\u0440\u043e\u0432\u043e\u0439 \u0446\u0438\u043a\u043b \u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u0430\u0443\u0437\u044b<\/h3>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0441\u0430\u043c\u044b\u0439 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u0446\u0438\u043a\u043b. \u041f\u043e\u0442\u043e\u043c \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043b \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443: \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \u0432\u043a\u043b\u0430\u0434\u043a\u0443, \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0451\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u0434\u0440\u044b, \u0430 \u043f\u043e\u0441\u043b\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043e\u0433\u0440\u043e\u043c\u043d\u044b\u0439 <code>deltaTime<\/code>.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0435\u0433\u043e \u0432 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0435 \u0438\u0433\u0440\u043e\u043a\u0430, \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436 \u043f\u043e\u0441\u043b\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0441\u0442\u0435\u043d\u0443.<\/p>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 <code>Loop<\/code> \u0435\u0441\u0442\u044c \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0448\u0430\u0433\u0430:<\/p>\n<pre><code>export class Loop {  private readonly maxDeltaSeconds: number  private previousTimeMilliseconds = 0  private elapsedSeconds = 0  private animationFrameId: number | null = null  public constructor(    private readonly update: (delta: number, elapsed: number) =&gt; void,    options: { maxDeltaSeconds?: number } = {},  ) {    this.maxDeltaSeconds = options.maxDeltaSeconds ?? 0.1  }  private readonly tick = (timeMilliseconds: number): void =&gt; {    if (this.animationFrameId === null) {      return    }    const rawDelta = Math.max(      0,      (timeMilliseconds - this.previousTimeMilliseconds) \/ 1000,    )    const delta = Math.min(rawDelta, this.maxDeltaSeconds)    this.previousTimeMilliseconds = timeMilliseconds    this.elapsedSeconds += delta    this.update(delta, this.elapsedSeconds)    this.animationFrameId = requestAnimationFrame(this.tick)  }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430\u043a\u0430\u043f\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f <code>elapsedSeconds<\/code>, \u0430 \u043f\u0440\u0438 \u043f\u0430\u0443\u0437\u0435 \u0446\u0438\u043a\u043b \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e. \u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 <code>0.1<\/code> \u0441\u0435\u043a\u0443\u043d\u0434\u044b \u2014 \u044d\u0442\u043e \u0441\u0442\u0440\u0430\u0445\u043e\u0432\u043a\u0430, \u0430 \u043d\u0435 \u0437\u0430\u043c\u0435\u043d\u0430 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430.<\/p>\n<h3>\u0422\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0448\u0438\u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439<\/h3>\n<p>\u041c\u043d\u0435 \u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c, \u0447\u0442\u043e\u0431\u044b UI \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043b <code>GameScene<\/code>, \u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043a\u043e\u0434 \u043d\u0430\u0447\u0438\u043d\u0430\u043b \u0437\u043d\u0430\u0442\u044c \u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 Vue-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445. \u0414\u043b\u044f \u0441\u0432\u044f\u0437\u0438 \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439 \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 <code>EventBus<\/code>.<\/p>\n<p>\u0421\u043e\u0431\u044b\u0442\u0438\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u043e\u0434\u043d\u043e\u0439 \u043a\u0430\u0440\u0442\u043e\u0439:<\/p>\n<pre><code>export interface GameEventMap {  'ui:graphics-changed': {    readonly quality: 'normal' | 'potato'  }  'ui:mobile-move': {    readonly x: number    readonly y: number  }  'interaction:door-selected': {    readonly answer: boolean    readonly doorId: 'anomaly' | 'no-anomaly'    readonly objectName: 'CorrectDoor' | 'WrongDoor'  }  'round:started': {    readonly level: number    readonly anomalyId: string | null    readonly hasAnomaly: boolean  }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e TypeScript \u043d\u0435 \u0434\u0430\u0441\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0441 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u043c payload:<\/p>\n<pre><code>gameEventBus.emit('interaction:door-selected', {  answer: true,  doorId: 'anomaly',  objectName: 'CorrectDoor',})gameEventBus.on('round:started', (round) =&gt; {  console.log(round.level, round.anomalyId)})<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0418\u0433\u0440\u043e\u0432\u043e\u0439 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0432\u044b\u0431\u043e\u0440\u0430 \u0434\u0432\u0435\u0440\u0438:<\/p>\n<pre><code>this.eventBus.on(  'interaction:door-selected',  ({ answer }) =&gt; this.evaluateDoor(answer),)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u043b\u044f \u043c\u0435\u043d\u044f \u0437\u0434\u0435\u0441\u044c \u0432\u0430\u0436\u043d\u0430 \u043d\u0435 \u0441\u0430\u043c\u0430 \u0448\u0438\u043d\u0430, \u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438. UI \u0437\u043d\u0430\u0435\u0442 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0439. \u0418\u0433\u0440\u043e\u0432\u043e\u0439 \u0441\u043b\u043e\u0439 \u0437\u043d\u0430\u0435\u0442, \u0447\u0442\u043e \u044d\u0442\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043e\u0437\u043d\u0430\u0447\u0430\u044e\u0442. \u041d\u043e UI \u043d\u0435 \u0437\u043d\u0430\u0435\u0442, \u0432 \u043a\u0430\u043a\u043e\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u0435 Three.js \u043b\u0435\u0436\u0438\u0442 \u0434\u0432\u0435\u0440\u044c \u0438 \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0435\u0451 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f.<\/p>\n<h3>\u0421\u0446\u0435\u043d\u0430 \u0438\u0437 Blender: \u0434\u043e\u0433\u043e\u0432\u043e\u0440 \u0432\u0430\u0436\u043d\u0435\u0435 \u043c\u0430\u0433\u0438\u0438<\/h3>\n<p>\u0423\u0440\u043e\u0432\u0435\u043d\u044c \u0441\u043e\u0431\u0438\u0440\u0430\u043b\u0441\u044f \u0432 Blender \u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0441\u044f \u0432 <code>level.glb<\/code>. \u042f \u043d\u0435 \u0445\u043e\u0442\u0435\u043b \u0437\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 TypeScript. \u042d\u0442\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0432 \u043d\u0430\u0431\u043e\u0440 \u0447\u0438\u0441\u0435\u043b, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u043e \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c.<\/p>\n<p>\u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u0443 \u0441\u0446\u0435\u043d\u044b \u0435\u0441\u0442\u044c \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0451\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u0438 \u0438\u043c\u0435\u043d\u0430\u043c:<\/p>\n<pre><code>Scene\u251c\u2500\u2500 StaticGeometry\u251c\u2500\u2500 Gameplay\u2502   \u251c\u2500\u2500 PlayerSpawn\u2502   \u251c\u2500\u2500 CorrectDoor\u2502   \u251c\u2500\u2500 WrongDoor\u2502   \u2514\u2500\u2500 AnomalyObjects\u251c\u2500\u2500 InteractiveDoors\u251c\u2500\u2500 Colliders\u2514\u2500\u2500 Lights<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0433\u0440\u0443\u043f\u043f\u044b \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0439:<\/p>\n<pre><code>AnomalyObjects\u251c\u2500\u2500 FlipFlopObj\u2502   \u251c\u2500\u2500 CHAIR_easy\u2502   \u251c\u2500\u2500 LAMP_medium\u2502   \u2514\u2500\u2500 BOTTLE_hard\u251c\u2500\u2500 FlipTextureObj\u2502   \u251c\u2500\u2500 Painting01_easy\u2502   \u2514\u2500\u2500 Sign01_hard\u2514\u2500\u2500 SpriteAnomalyPoints    \u251c\u2500\u2500 Hallway_easy    \u2514\u2500\u2500 Doorway_hard<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0421\u0443\u0444\u0444\u0438\u043a\u0441 \u0432 \u0438\u043c\u0435\u043d\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u2014 \u044d\u0442\u043e \u043d\u0435 \u0447\u0430\u0441\u0442\u044c \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0432 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u043c \u0441\u043c\u044b\u0441\u043b\u0435. \u042d\u0442\u043e \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439 DSL \u0443\u0440\u043e\u0432\u043d\u044f:<\/p>\n<ul>\n<li>\n<p><code>_easy<\/code> \u2014 \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u044f;<\/p>\n<\/li>\n<li>\n<p><code>_medium<\/code> \u2014 \u0441\u0440\u0435\u0434\u043d\u044f\u044f;<\/p>\n<\/li>\n<li>\n<p><code>_hard<\/code> \u2014 \u0441\u043b\u043e\u0436\u043d\u0430\u044f.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<ol>\n<li>\n<p>\u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438\u043b\u0438 \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 Blender;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u043d\u0443\u0436\u043d\u0443\u044e \u0433\u0440\u0443\u043f\u043f\u0443;<\/p>\n<\/li>\n<li>\n<p>\u043d\u0430\u0437\u0432\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u043c \u0441\u0443\u0444\u0444\u0438\u043a\u0441\u043e\u043c;<\/p>\n<\/li>\n<li>\n<p>\u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c GLB.<\/p>\n<\/li>\n<\/ol>\n<p>\u0412 \u043a\u043e\u0434\u0435 \u043d\u0435 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0439 <code>if<\/code> \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u0442\u0443\u043b\u0430 \u0438\u043b\u0438 \u043a\u0430\u0440\u0442\u0438\u043d\u044b.<\/p>\n<h4>\u041a\u0430\u043a \u0434\u0432\u0438\u0436\u043e\u043a \u043d\u0430\u0445\u043e\u0434\u0438\u0442 \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0438<\/h4>\n<p>\u041f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 GLB \u0434\u0432\u0438\u0436\u043e\u043a \u0441\u043a\u0430\u043d\u0438\u0440\u0443\u0435\u0442 \u043f\u0440\u044f\u043c\u044b\u0445 \u0434\u0435\u0442\u0435\u0439 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u0433\u0440\u0443\u043f\u043f \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0438\u0445 \u0438\u043c\u0435\u043d\u0430:<\/p>\n<pre><code>const DIFFICULTY_BY_SUFFIX = {  easy: 'Easy',  medium: 'Medium',  hard: 'Hard',} as constfunction parseDefinition(  object: Object3D,  kind: LevelAnomalyKind,): LevelAnomalyDefinition | string {  const match = \/_(easy|medium|hard)$\/i.exec(object.name)  if (match === null) {    return `Object \"${object.name}\" has no difficulty suffix.`  }  const suffix = match[1].toLowerCase()  const difficulty = DIFFICULTY_BY_SUFFIX[suffix]  const assetBaseName = object.name.slice(0, match.index).trim()  return {    kind,    difficulty,    targetObjectId: object.name,    assetBaseName,  }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u043e\u0431\u044a\u0435\u043a\u0442 \u043d\u0430\u0437\u0432\u0430\u043d \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e, \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0430\u0434\u0430\u0435\u0442 \u0446\u0435\u043b\u0438\u043a\u043e\u043c. \u0414\u0432\u0438\u0436\u043e\u043a \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 recoverable error, \u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0430\u044f \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u0430\u044f \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0438\u0437 \u043f\u0443\u043b\u043e\u0432. \u042d\u0442\u043e \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u0435\u0435, \u0447\u0435\u043c \u0431\u0435\u043b\u044b\u0439 \u044d\u043a\u0440\u0430\u043d \u0438\u0437-\u0437\u0430 \u043e\u0434\u043d\u043e\u0439 \u043e\u043f\u0435\u0447\u0430\u0442\u043a\u0438 \u0432 Blender.<\/p>\n<h3>\u041e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u0435: \u0432 production-\u0441\u0446\u0435\u043d\u0435 \u043d\u0435\u0442 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u0441\u0432\u0435\u0442\u0430<\/h3>\n<p>\u0412 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u0446\u0435\u043d\u0435 \u044f \u043f\u043e\u0448\u0451\u043b \u043f\u043e \u043f\u0443\u0442\u0438 \u0437\u0430\u043f\u0435\u0447\u0451\u043d\u043d\u043e\u0433\u043e \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u044f. \u0412 <code>level.glb<\/code> \u043d\u0435\u0442 \u0440\u0430\u0431\u043e\u0447\u0438\u0445 <code>PointLight<\/code>, <code>SpotLight<\/code> \u0438\u043b\u0438 <code>DirectionalLight<\/code>. \u0413\u0440\u0443\u043f\u043f\u0430 <code>Lights<\/code> \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0441\u0446\u0435\u043d\u044b, \u043d\u043e \u0441\u0430\u043c\u0430 production-\u0441\u0446\u0435\u043d\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u044e \u0438 \u0443\u0436\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b.<\/p>\n<p>\u041d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 Three.js \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0435 \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0435\u043d\u0438:<\/p>\n<pre><code>this.instance = new WebGLRenderer({  antialias: false,  powerPreference: 'high-performance',})this.instance.shadowMap.enabled = false<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u043b\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u0441 \u0443\u0436\u0435 \u0437\u0430\u043f\u0435\u0447\u0451\u043d\u043d\u044b\u043c\u0438 \u0441\u0432\u0435\u0442\u043e\u043c \u0438 \u0442\u0435\u043d\u044f\u043c\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u043e\u0449\u0435, \u0447\u0435\u043c \u0432 \u0441\u0446\u0435\u043d\u0435 \u0441 realtime lighting:<\/p>\n<pre><code>texture.flipY = falseapplyPS1TextureStyle(texture)mesh.material = new MeshBasicMaterial({  map: texture,})<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>MeshBasicMaterial<\/code> \u043d\u0435 \u0443\u0447\u0430\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0440\u0430\u0441\u0447\u0451\u0442\u0435 \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u044f. \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u043d\u0435 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a, \u0430 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435: \u0441\u0432\u0435\u0442 \u0443\u0436\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0446\u0432\u0435\u0442\u0435 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b.<\/p>\n<h4>\u0427\u0442\u043e \u0431\u044b\u043b\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u043c \u043f\u0440\u0438 \u0437\u0430\u043f\u0435\u043a\u0430\u043d\u0438\u0438<\/h4>\n<p>\u0417\u0430\u043f\u0435\u0447\u044c \u0441\u0432\u0435\u0442 \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u2014 \u043d\u0435 \u0437\u043d\u0430\u0447\u0438\u0442 \u043d\u0430\u0436\u0430\u0442\u044c \u043e\u0434\u043d\u0443 \u043a\u043d\u043e\u043f\u043a\u0443 \u0438 \u0437\u0430\u0431\u044b\u0442\u044c \u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0435. \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0431\u044b\u043b\u0438 \u0442\u0430\u043a\u0438\u043c\u0438.<\/p>\n<p>\u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0441\u043b\u0435\u0434\u0438\u0442\u044c \u0437\u0430 UV-\u0440\u0430\u0437\u0432\u0451\u0440\u0442\u043a\u043e\u0439 \u0438 \u043e\u0442\u0441\u0442\u0443\u043f\u0430\u043c\u0438 \u043c\u0435\u0436\u0434\u0443 \u043e\u0441\u0442\u0440\u043e\u0432\u0430\u043c\u0438. \u041d\u0430 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u0439 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439 padding \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u0432\u0435\u0442\u043b\u044b\u0435 \u0438\u043b\u0438 \u0442\u0451\u043c\u043d\u044b\u0435 \u0448\u0432\u044b \u043f\u043e\u0441\u043b\u0435 \u0441\u0436\u0430\u0442\u0438\u044f \u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<p>\u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, low-poly-\u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u044f \u0438 PS1-\u0441\u0442\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u043b\u043e\u0445\u043e \u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0442 \u043e\u0448\u0438\u0431\u043a\u0438. \u0412 \u0440\u0435\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d\u043e\u0439 \u0441\u0446\u0435\u043d\u0435 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043c\u0430\u0441\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u044f\u0433\u043a\u0438\u043c \u0441\u0432\u0435\u0442\u043e\u043c, \u0442\u0443\u043c\u0430\u043d\u043e\u043c \u0438\u043b\u0438 \u043f\u043e\u0441\u0442\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439. \u0417\u0434\u0435\u0441\u044c \u043b\u044e\u0431\u0430\u044f \u0433\u0440\u044f\u0437\u043d\u0430\u044f \u043f\u043e\u043b\u043e\u0441\u0430 \u043d\u0430 \u0441\u0442\u0435\u043d\u0435 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e \u0437\u0430\u043c\u0435\u0442\u043d\u043e\u0433\u043e \u043f\u0438\u043a\u0441\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0443\u0437\u043e\u0440\u0430.<\/p>\n<p>\u0412-\u0442\u0440\u0435\u0442\u044c\u0438\u0445, \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0438 \u043c\u0435\u043d\u044f\u044e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043a\u043e\u043c\u043d\u0430\u0442\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u043e\u0434\u0438\u043d \u0446\u0438\u043a\u043b. \u0415\u0441\u043b\u0438 \u0443 \u043a\u0430\u0440\u0442\u0438\u043d\u044b \u0435\u0441\u0442\u044c \u043e\u0431\u044b\u0447\u043d\u0430\u044f \u0438 \u0430\u043d\u043e\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f, \u043e\u0431\u0435 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a, \u0431\u0443\u0434\u0442\u043e \u043e\u043d\u0438 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u0439 \u0438 \u0442\u043e\u0439 \u0436\u0435 \u0441\u0446\u0435\u043d\u0435. \u0418\u043d\u0430\u0447\u0435 \u0438\u0433\u0440\u043e\u043a \u0437\u0430\u043c\u0435\u0447\u0430\u0435\u0442 \u043d\u0435 \u0441\u0430\u043c\u0443 \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u044e, \u0430 \u0442\u043e, \u0447\u0442\u043e \u0443 \u043d\u0435\u0451 \u0432\u043d\u0435\u0437\u0430\u043f\u043d\u043e \u0434\u0440\u0443\u0433\u043e\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u044f.<\/p>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u0432 \u0441\u0446\u0435\u043d\u0435 \u0435\u0441\u0442\u044c \u043a\u043e\u043b\u043b\u0430\u0439\u0434\u0435\u0440\u044b \u0438 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u043f\u0430\u0434\u0430\u0442\u044c \u0432 \u0438\u0442\u043e\u0433\u043e\u0432\u0443\u044e \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0443. \u041e\u043d\u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0433\u0440\u0443\u043f\u043f\u044b \u0438 \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438:<\/p>\n<pre><code>private prepareCollisionMesh(mesh: Mesh): void {  mesh.visible = false  mesh.material = new MeshBasicMaterial({ side: DoubleSide })  mesh.userData['collisionOnly'] = true}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0430\u043a \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u0430\u044f \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u044f \u0438 \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u044f \u0441\u0442\u043e\u043b\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0439 \u0436\u0438\u0432\u0443\u0442 \u0432 \u043e\u0434\u043d\u043e\u043c GLB, \u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442 \u0440\u0430\u0437\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438.<\/p>\n<h3>\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 GLB, \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u0438 Draco<\/h3>\n<p>\u041f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d-\u0443\u0440\u043e\u0432\u0435\u043d\u044c \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d \u0432 GLB \u0441 Draco-\u0441\u0436\u0430\u0442\u0438\u0435\u043c. \u0414\u043b\u044f \u0435\u0433\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>GLTFLoader<\/code> \u0438 <code>DRACOLoader<\/code>:<\/p>\n<pre><code>this.loader = new ThreeGLTFLoader(manager)this.dracoLoader = new DRACOLoader(manager)this.dracoLoader.setDecoderPath(DRACO_GLTF_CONFIG)this.loader.setDRACOLoader(this.dracoLoader)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0421\u0430\u043c \u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a \u043a\u0435\u0448\u0438\u0440\u0443\u0435\u0442 \u043d\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u0430 <code>Promise<\/code>:<\/p>\n<pre><code>public load(url: string): Promise&lt;GLTF&gt; {  const cached = this.cache.get(url)  if (cached !== undefined) {    return cached  }  const request = this.loader.loadAsync(url)  this.cache.set(url, request)  return request.catch((error) =&gt; {    this.cache.delete(url)    throw error  })}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u0442 \u043e\u0442 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0438 \u0442\u043e\u0433\u043e \u0436\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430, \u043a\u043e\u0433\u0434\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u0441\u0438\u0441\u0442\u0435\u043c \u043f\u043e\u0447\u0442\u0438 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0438\u043b\u0438 \u043c\u043e\u0434\u0435\u043b\u044c.<\/p>\n<p>\u0427\u0430\u0441\u0442\u044c \u0442\u0435\u043a\u0441\u0442\u0443\u0440 \u043b\u0435\u0436\u0438\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0442 GLB. \u042d\u0442\u043e \u0431\u044b\u043b\u043e \u0443\u0434\u043e\u0431\u043d\u043e \u0434\u043b\u044f \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0439: \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0432\u0441\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u0440\u0430\u0434\u0438 \u0437\u0430\u043c\u0435\u043d\u044b \u043e\u0434\u043d\u043e\u0439 \u043a\u0430\u0440\u0442\u0438\u043d\u044b.<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 <code>Painting01_medium<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f:<\/p>\n<pre><code>textures\/Painting01_v1.png \u2014 \u043e\u0431\u044b\u0447\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435textures\/Painting01_v2.png \u2014 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441 \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0435\u0439<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u0435\u0442 \u043c\u0435\u0448\u0438 \u043f\u043e URL \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u043a\u0430\u0436\u0434\u044b\u0439 URL \u043e\u0434\u0438\u043d \u0440\u0430\u0437. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043e\u0434\u043d\u0430 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c.<\/p>\n<p>\u0412 production-\u0441\u0431\u043e\u0440\u043a\u0435 \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0443\u0436\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c Draco-\u0434\u0435\u043a\u043e\u0434\u0435\u0440\u0430. \u042d\u0442\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0430\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0431\u0430\u043d\u0434\u043b\u0430: \u043f\u0440\u043e\u0435\u043a\u0442\u0443 \u043d\u0443\u0436\u0435\u043d \u0434\u0435\u043a\u043e\u0434\u0435\u0440 GLB, \u043d\u043e \u043d\u0435 \u0432\u0441\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0438\u0437 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 Three.js.<\/p>\n<h3>\u0410\u043d\u043e\u043c\u0430\u043b\u0438\u044f \u043a\u0430\u043a \u043e\u0431\u0440\u0430\u0442\u0438\u043c\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<\/h3>\n<p>\u042f \u043d\u0435 \u0441\u0442\u0430\u043b \u0434\u0435\u043b\u0430\u0442\u044c \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0438 \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u0435\u043d\u044f\u044e\u0442 \u0441\u0446\u0435\u043d\u0443 \u0438 \u043d\u0430\u0434\u0435\u044e\u0442\u0441\u044f, \u0447\u0442\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0440\u0430\u0443\u043d\u0434 \u0432\u0441\u0451 \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442. \u0423 \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0438 \u0435\u0441\u0442\u044c \u044f\u0432\u043d\u044b\u0439 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u0439 \u0446\u0438\u043a\u043b:<\/p>\n<pre><code>export interface Anomaly {  readonly id: string  readonly difficulty: AnomalyDifficulty  readonly targetObjectId: string  readonly isApplied: boolean  apply(): void  reset(): void}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u043d\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442 \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0432\u0435 \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0438 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e:<\/p>\n<pre><code>export class AnomalyManager {  private current: Anomaly | null = null  public activate(anomaly: Anomaly): void {    if (this.current === anomaly) {      return    }    if (this.current !== null &amp;&amp; this.current !== anomaly) {      throw new Error('Another anomaly is already active.')    }    anomaly.apply()    this.current = anomaly  }  public reset(): void {    this.current?.reset()    this.current = null  }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0435\u0440 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0438\u0441\u0445\u043e\u0434\u043d\u0443\u044e \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c:<\/p>\n<pre><code>const snapshot = {  object,  visible: object.visible,}object.visible = false\/\/ \u041f\u043e\u0441\u043b\u0435 \u043e\u0442\u0432\u0435\u0442\u0430 \u0438\u0433\u0440\u043e\u043a\u0430snapshot.object.visible = snapshot.visible<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u043b\u044f \u0437\u0430\u043c\u0435\u043d\u044b \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b. \u041d\u043e\u0432\u044b\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043a\u043b\u043e\u043d\u0438\u0440\u0443\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0432\u0441\u0435\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0442\u043e\u0442 \u0436\u0435 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440:<\/p>\n<pre><code>const original = mesh.materialconst anomaly = createAnomalyMaterial(original, anomalyTexture)mesh.material = anomaly\/\/ resetmesh.material = originalanomaly.dispose()<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u043a\u043e\u0434\u0430, \u0447\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u0438\u0441\u0432\u043e\u0438\u0442\u044c <code>visible = false<\/code>, \u043d\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0440\u0430\u0443\u043d\u0434\u0430 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0442\u0438\u043c\u044b\u043c. \u041f\u043e\u0441\u043b\u0435 \u043e\u0442\u0432\u0435\u0442\u0430 \u0438\u0433\u0440\u043e\u043a\u0430 \u043c\u043e\u0436\u043d\u043e \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0441\u0446\u0435\u043d\u0443 \u043a \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c\u0443 \u0432\u0438\u0434\u0443.<\/p>\n<h3>\u041a\u0430\u043a \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442\u0441\u044f \u0443\u0440\u043e\u0432\u043d\u0438 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438<\/h3>\n<p>\u0412 \u0438\u0433\u0440\u0435 \u0434\u0435\u0432\u044f\u0442\u044c \u0446\u0438\u043a\u043b\u043e\u0432 \u2014 \u043e\u0442 <code>0<\/code> \u0434\u043e <code>8<\/code>. \u041d\u0443\u043b\u0435\u0432\u043e\u0439 \u0446\u0438\u043a\u043b \u0432\u0441\u0435\u0433\u0434\u0430 \u0447\u0438\u0441\u0442\u044b\u0439. \u0414\u043b\u044f \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u0432\u0435\u0441\u043e\u0432:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u0423\u0440\u043e\u0432\u0435\u043d\u044c<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u041d\u0435\u0442 \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0438<\/p>\n<\/th>\n<th>\n<p align=\"left\">Easy<\/p>\n<\/th>\n<th>\n<p align=\"left\">Medium<\/p>\n<\/th>\n<th>\n<p align=\"left\">Hard<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">0<\/p>\n<\/td>\n<td>\n<p align=\"left\">100<\/p>\n<\/td>\n<td>\n<p align=\"left\">0<\/p>\n<\/td>\n<td>\n<p align=\"left\">0<\/p>\n<\/td>\n<td>\n<p align=\"left\">0<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">1<\/p>\n<\/td>\n<td>\n<p align=\"left\">30<\/p>\n<\/td>\n<td>\n<p align=\"left\">56<\/p>\n<\/td>\n<td>\n<p align=\"left\">14<\/p>\n<\/td>\n<td>\n<p align=\"left\">0<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">2<\/p>\n<\/td>\n<td>\n<p align=\"left\">30<\/p>\n<\/td>\n<td>\n<p align=\"left\">49<\/p>\n<\/td>\n<td>\n<p align=\"left\">17<\/p>\n<\/td>\n<td>\n<p align=\"left\">4<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">3<\/p>\n<\/td>\n<td>\n<p align=\"left\">30<\/p>\n<\/td>\n<td>\n<p align=\"left\">35<\/p>\n<\/td>\n<td>\n<p align=\"left\">28<\/p>\n<\/td>\n<td>\n<p align=\"left\">7<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">4<\/p>\n<\/td>\n<td>\n<p align=\"left\">30<\/p>\n<\/td>\n<td>\n<p align=\"left\">21<\/p>\n<\/td>\n<td>\n<p align=\"left\">35<\/p>\n<\/td>\n<td>\n<p align=\"left\">14<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">5<\/p>\n<\/td>\n<td>\n<p align=\"left\">30<\/p>\n<\/td>\n<td>\n<p align=\"left\">17<\/p>\n<\/td>\n<td>\n<p align=\"left\">35<\/p>\n<\/td>\n<td>\n<p align=\"left\">18<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">6<\/p>\n<\/td>\n<td>\n<p align=\"left\">30<\/p>\n<\/td>\n<td>\n<p align=\"left\">14<\/p>\n<\/td>\n<td>\n<p align=\"left\">35<\/p>\n<\/td>\n<td>\n<p align=\"left\">21<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">7<\/p>\n<\/td>\n<td>\n<p align=\"left\">30<\/p>\n<\/td>\n<td>\n<p align=\"left\">11<\/p>\n<\/td>\n<td>\n<p align=\"left\">31<\/p>\n<\/td>\n<td>\n<p align=\"left\">28<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">8<\/p>\n<\/td>\n<td>\n<p align=\"left\">30<\/p>\n<\/td>\n<td>\n<p align=\"left\">7<\/p>\n<\/td>\n<td>\n<p align=\"left\">28<\/p>\n<\/td>\n<td>\n<p align=\"left\">35<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u042d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0446\u0435\u043d\u0442\u044b \u0432 \u0441\u0442\u0440\u043e\u0433\u043e\u043c \u0441\u043c\u044b\u0441\u043b\u0435, \u0430 \u0432\u0435\u0441\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 \u043f\u0435\u0440\u0432\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435 \u0441\u0443\u043c\u043c\u0430 \u0440\u0430\u0432\u043d\u0430 100, \u0430 \u043d\u0430 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u2014 100 \u0442\u043e\u0436\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0447\u0438\u0442\u0430\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u043a\u0430\u043a \u043f\u0440\u043e\u0446\u0435\u043d\u0442\u044b \u0443\u0434\u043e\u0431\u043d\u043e.<\/p>\n<p>\u0412\u044b\u0431\u043e\u0440 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0441\u0434\u0435\u043b\u0430\u043d \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0442 \u0432\u044b\u0431\u043e\u0440\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0438:<\/p>\n<pre><code>const selectedDifficulty = selectWeightedDifficulty(  config.weights,  this.random,)const difficulty = consecutiveClearRounds &gt;= 2  ? RoundDifficulty.Hard  : selectedDifficulty<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u043d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0438\u0433\u0440\u0430 \u043d\u0435 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u043b\u0430\u0441\u044c \u0432 \u0441\u0435\u0440\u0438\u044e \u043f\u0443\u0441\u0442\u044b\u0445 \u043a\u043e\u043c\u043d\u0430\u0442. \u0415\u0441\u043b\u0438 \u0434\u0432\u0430 \u0440\u0430\u0437\u0430 \u043f\u043e\u0434\u0440\u044f\u0434 \u0432\u044b\u043f\u0430\u043b \u0446\u0438\u043a\u043b \u0431\u0435\u0437 \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0438, \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0440\u0430\u0443\u043d\u0434 \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u0443\u044e \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u044e.<\/p>\n<h4>\u041f\u043e\u0447\u0435\u043c\u0443 \u043e\u0431\u044b\u0447\u043d\u043e\u0433\u043e random \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e<\/h4>\n<p>\u0415\u0441\u043b\u0438 \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0439 \u0432\u044b\u0431\u043e\u0440 \u0438\u0437 \u043c\u0430\u0441\u0441\u0438\u0432\u0430, \u043e\u0434\u043d\u0430 \u0438 \u0442\u0430 \u0436\u0435 \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u043f\u0430\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u043f\u043e\u0434\u0440\u044f\u0434, \u0430 \u0434\u0440\u0443\u0433\u0430\u044f \u0434\u043e\u043b\u0433\u043e \u043d\u0435 \u043f\u043e\u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f.<\/p>\n<p>\u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>ShuffleBag<\/code>. \u041e\u043d \u043f\u0435\u0440\u0435\u043c\u0435\u0448\u0438\u0432\u0430\u0435\u0442 \u043f\u0443\u043b, \u0432\u044b\u0434\u0430\u0451\u0442 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u043f\u043e \u043e\u0434\u043d\u043e\u043c\u0443 \u0438 \u043d\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0437\u0430\u043d\u043e\u0432\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043f\u0443\u043b \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0441\u044f. \u041f\u0440\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0432\u044b\u0434\u0430\u043d\u043d\u0430\u044f \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u044f \u043d\u0435 \u0441\u0442\u0430\u043b\u0430 \u043f\u0435\u0440\u0432\u043e\u0439 \u0432 \u043d\u043e\u0432\u043e\u043c \u0446\u0438\u043a\u043b\u0435.<\/p>\n<p>\u0422\u0430\u043a \u0440\u0430\u043d\u0434\u043e\u043c \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0440\u0430\u043d\u0434\u043e\u043c\u043e\u043c, \u043d\u043e \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0451\u0442 \u0431\u044b\u0442\u044c \u0440\u0430\u0437\u0434\u0440\u0430\u0436\u0430\u044e\u0449\u0438\u043c.<\/p>\n<h3>PS1-\u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433: \u043d\u0435 \u043e\u0434\u0438\u043d \u0444\u0438\u043b\u044c\u0442\u0440 \u043f\u043e\u0432\u0435\u0440\u0445 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438<\/h3>\n<p>\u041c\u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0449\u0443\u0449\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u0440\u044b\u0445 \u0438\u0433\u0440 \u0434\u043b\u044f PlayStation, \u043d\u043e \u043e\u0434\u043d\u043e\u0433\u043e \u0446\u0432\u0435\u0442\u043e\u0432\u043e\u0433\u043e \u0444\u0438\u043b\u044c\u0442\u0440\u0430 \u0431\u044b\u043b\u043e \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044d\u0444\u0444\u0435\u043a\u0442 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0447\u0430\u0441\u0442\u0435\u0439.<\/p>\n<h4>1. \u0421\u0446\u0435\u043d\u0430 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0438\u0441\u0443\u0435\u0442\u0441\u044f \u0432 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435<\/h4>\n<p>\u0412\u043c\u0435\u0441\u0442\u043e \u0440\u0435\u043d\u0434\u0435\u0440\u0430 \u0441\u0440\u0430\u0437\u0443 \u0432 \u0440\u0430\u0437\u043c\u0435\u0440 canvas \u0441\u0446\u0435\u043d\u0430 \u0440\u0438\u0441\u0443\u0435\u0442\u0441\u044f \u0432 <code>WebGLRenderTarget<\/code>:<\/p>\n<pre><code>public render(  renderer: WebGLRenderer,  scene: Scene,  camera: Camera,): void {  renderer.setRenderTarget(this.target)  renderer.clear()  renderer.render(scene, camera)  renderer.setRenderTarget(null)  renderer.clear()  renderer.render(this.outputScene, this.outputCamera)}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0435\u043a\u0441\u0442\u0443\u0440\u0430 target \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u044d\u043a\u0440\u0430\u043d \u0441 <code>NearestFilter<\/code>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0438\u043a\u0441\u0435\u043b\u0438 \u043d\u0435 \u0441\u0433\u043b\u0430\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f.<\/p>\n<h4>2. \u0422\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0431\u0438\u043b\u0438\u043d\u0435\u0439\u043d\u0443\u044e \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044e<\/h4>\n<pre><code>export function applyPS1TextureStyle(texture: Texture): void {  texture.magFilter = NearestFilter  texture.minFilter = NearestFilter  texture.generateMipmaps = false  texture.anisotropy = 1  texture.needsUpdate = true}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 mipmap \u0438 anisotropy \u0437\u0434\u0435\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e. \u0412 \u043e\u0431\u044b\u0447\u043d\u043e\u0439 \u0438\u0433\u0440\u0435 \u044d\u0442\u043e \u043c\u043e\u0433\u043b\u043e \u0431\u044b \u0443\u0445\u0443\u0434\u0448\u0438\u0442\u044c \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u0434\u0430\u043b\u0438 \u043e\u0442 \u043a\u0430\u043c\u0435\u0440\u044b, \u043d\u043e \u0434\u043b\u044f \u043d\u0443\u0436\u043d\u043e\u0433\u043e \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0441\u0442\u0438\u043b\u044f \u0442\u0430\u043a\u043e\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u043b\u0443\u0447\u0448\u0435.<\/p>\n<h4>3. \u0412\u0435\u0440\u0448\u0438\u043d\u044b \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043a \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u0438\u043a\u0441\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0435\u0442\u043a\u0435<\/h4>\n<p>\u0412\u0435\u0440\u0448\u0438\u043d\u043d\u044b\u0439 \u0448\u0435\u0439\u0434\u0435\u0440 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u0442 \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u0432 NDC, \u043e\u043a\u0440\u0443\u0433\u043b\u044f\u0435\u0442 \u0435\u0451 \u0434\u043e \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u0435\u0442\u043a\u0438 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0431\u0440\u0430\u0442\u043d\u043e:<\/p>\n<pre><code>vec2 ndc = projected.xy \/ projected.w;vec2 pixelPosition = (ndc * 0.5 + 0.5) * ps1SnapResolution;pixelPosition = floor(pixelPosition + 0.5);ndc = (pixelPosition \/ ps1SnapResolution) * 2.0 - 1.0;projected.xy = ndc * projected.w;gl_Position = projected;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0411\u0435\u0437 \u044d\u0442\u043e\u0433\u043e \u043a\u0430\u043c\u0435\u0440\u0430 \u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u00ab\u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u00bb: \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u043f\u0438\u043a\u0441\u0435\u043b\u044c\u043d\u044b\u0435, \u0430 \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u0442 \u0434\u0432\u0438\u0433\u0430\u0442\u044c\u0441\u044f \u043f\u043b\u0430\u0432\u043d\u043e.<\/p>\n<h4>4. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f ordered dithering<\/h4>\n<p>\u0412 \u043f\u043e\u0441\u0442\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0438\u043d\u0433\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u0430\u0442\u0440\u0438\u0446\u0430 Bayer 4\u00d74. \u041e\u043d\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u043c\u043e\u0435 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043e\u0442\u0442\u0435\u043d\u043a\u043e\u0432 \u0438 \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043d\u0443\u044e \u0441\u0442\u0443\u043f\u0435\u043d\u0447\u0430\u0442\u0443\u044e \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0443 \u0432 \u0442\u0451\u043c\u043d\u044b\u0445 \u043e\u0431\u043b\u0430\u0441\u0442\u044f\u0445.<\/p>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 PS1-\u044d\u0444\u0444\u0435\u043a\u0442 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0441\u0442\u0430\u043b \u0447\u0430\u0441\u0442\u044c\u044e \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0441\u0442\u0438\u043b\u044f \u0438 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u0440\u0435\u043d\u0434\u0435\u0440\u0430.<\/p>\n<h3>\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u043e\u0434 \u0441\u043b\u0430\u0431\u044b\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430<\/h3>\n<p>\u0411\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u0430\u044f \u0438\u0433\u0440\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u043c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435. \u0412 \u042f\u043d\u0434\u0435\u043a\u0441 \u0418\u0433\u0440\u0430\u0445 \u043d\u0443\u0436\u043d\u043e \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u0440\u044b\u0435 \u043d\u043e\u0443\u0442\u0431\u0443\u043a\u0438, \u0431\u044e\u0434\u0436\u0435\u0442\u043d\u044b\u0435 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u044b \u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u044b \u0441 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u044b\u043c GPU.<\/p>\n<h4>\u0421\u043d\u0438\u0436\u0435\u043d\u0438\u0435 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f<\/h4>\n<p>\u0412 \u0438\u0433\u0440\u0435 \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u043f\u0440\u0435\u0441\u0435\u0442\u0430 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0438 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0432\u044b\u0441\u043e\u0442\u0430 target<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u041c\u0430\u0441\u0448\u0442\u0430\u0431 \u043e\u0442 CSS-\u0440\u0430\u0437\u043c\u0435\u0440\u0430<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Desktop \/ normal<\/p>\n<\/td>\n<td>\n<p align=\"left\">480<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.6<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Desktop \/ potato<\/p>\n<\/td>\n<td>\n<p align=\"left\">360<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.5<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Mobile \/ normal<\/p>\n<\/td>\n<td>\n<p align=\"left\">540<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.85<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Mobile \/ potato<\/p>\n<\/td>\n<td>\n<p align=\"left\">480<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.7<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0420\u0435\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 viewport:<\/p>\n<pre><code>const scaledHeight = Math.round(displayHeight * this.resolutionScale)const height = Math.min(scaledHeight, this.resolutionHeight)const width = Math.round(height * aspect)this.target.setSize(width, height)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u0435\u0441\u0435\u0442 \u043d\u0443\u0436\u0435\u043d \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0439 viewport \u0438 \u043f\u043b\u043e\u0442\u043d\u043e\u0441\u0442\u044c \u043f\u0438\u043a\u0441\u0435\u043b\u0435\u0439 \u0432\u0435\u0434\u0443\u0442 \u0441\u0435\u0431\u044f \u0438\u043d\u0430\u0447\u0435. \u042f \u043d\u0435 \u0441\u0442\u0430\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>window.devicePixelRatio<\/code> \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u2014 \u043d\u0430 Retina-\u044d\u043a\u0440\u0430\u043d\u0435 \u044d\u0442\u043e \u043c\u043e\u0433\u043b\u043e \u0431\u044b \u0443\u043c\u043d\u043e\u0436\u0438\u0442\u044c \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u0430\u0434\u0440\u0430.<\/p>\n<pre><code>this.instance.setPixelRatio(1)this.instance.setSize(width, height, false)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>\u0427\u0442\u043e \u0435\u0449\u0451 \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0435\u0442 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443<\/h4>\n<p>\u0412 \u0440\u0435\u043d\u0434\u0435\u0440\u0435\u0440\u0435 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u043e\u0435 \u0441\u0433\u043b\u0430\u0436\u0438\u0432\u0430\u043d\u0438\u0435 \u0438 realtime-\u0442\u0435\u043d\u0438:<\/p>\n<pre><code>new WebGLRenderer({  antialias: false,  powerPreference: quality === 'normal'    ? 'high-performance'    : 'low-power',})renderer.shadowMap.enabled = false<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041a\u0440\u043e\u043c\u0435 \u044d\u0442\u043e\u0433\u043e:<\/p>\n<ul>\n<li>\n<p>\u043e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u0446\u0435\u043d\u044b \u0437\u0430\u043f\u0435\u0447\u0435\u043d\u043e \u0432 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430\u0445;<\/p>\n<\/li>\n<li>\n<p>GLB \u0441\u0436\u0430\u0442 Draco;<\/p>\n<\/li>\n<li>\n<p>\u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u043a\u0435\u0448\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u043f\u043e URL;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u043d\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437;<\/p>\n<\/li>\n<li>\n<p>mipmap \u0438 anisotropy \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u0432 PS1-\u0440\u0435\u0436\u0438\u043c\u0435;<\/p>\n<\/li>\n<li>\n<p>\u043a\u043e\u043b\u043b\u0430\u0439\u0434\u0435\u0440\u044b \u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0438 \u043d\u0435 \u0443\u0447\u0430\u0441\u0442\u0432\u0443\u044e\u0442 \u0432 \u043e\u0431\u044b\u0447\u043d\u043e\u043c \u0440\u0435\u043d\u0434\u0435\u0440\u0435;<\/p>\n<\/li>\n<li>\n<p>\u043f\u0440\u0438 \u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0435\u043d\u0438\u0438 \u0441\u0446\u0435\u043d\u044b \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u044e\u0442\u0441\u044f \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0438, \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b, \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u0438 WebGL-\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442.<\/p>\n<\/li>\n<\/ul>\n<p>\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0438\u0437 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a UI \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u0441\u044f \u0432 <code>Renderer<\/code> \u0441\u043e\u0431\u044b\u0442\u0438\u0435\u043c:<\/p>\n<pre><code>gameEventBus.emit('ui:graphics-changed', {  quality: 'potato',})<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043c\u0435\u043d\u044f\u0442\u044c \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u043e FPS \u044f \u043d\u0435 \u0441\u0442\u0430\u043b. \u0414\u043b\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0438\u0433\u0440\u044b \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u044b\u0439 \u043f\u0440\u0435\u0441\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f \u043f\u043e\u043d\u044f\u0442\u043d\u0435\u0435: \u0438\u0433\u0440\u043e\u043a \u0441\u0430\u043c \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u00ab\u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u00bb \u0438\u043b\u0438 \u00ab\u0434\u043b\u044f \u0441\u043b\u0430\u0431\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u00bb, \u0430 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430 \u043d\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u043d\u0435\u043e\u0436\u0438\u0434\u0430\u043d\u043d\u043e \u043f\u0440\u044b\u0433\u0430\u0442\u044c \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f.<\/p>\n<h3>\u041f\u0430\u0443\u0437\u0430, \u0432\u043a\u043b\u0430\u0434\u043a\u0430 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0438 \u042f\u043d\u0434\u0435\u043a\u0441 \u0418\u0433\u0440\u044b<\/h3>\n<p>\u041f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0430 \u0435\u0449\u0451 \u043e\u0434\u0438\u043d \u043a\u043b\u0430\u0441\u0441 \u043f\u0440\u043e\u0431\u043b\u0435\u043c. \u041f\u0430\u0443\u0437\u0430 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0442\u0438 \u043f\u043e \u0440\u0430\u0437\u043d\u044b\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c:<\/p>\n<ul>\n<li>\n<p>\u0438\u0433\u0440\u043e\u043a \u0441\u0432\u0435\u0440\u043d\u0443\u043b \u0432\u043a\u043b\u0430\u0434\u043a\u0443;<\/p>\n<\/li>\n<li>\n<p>\u043e\u043a\u043d\u043e \u043f\u043e\u0442\u0435\u0440\u044f\u043b\u043e \u0444\u043e\u043a\u0443\u0441;<\/p>\n<\/li>\n<li>\n<p>\u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043b <code>pagehide<\/code>;<\/p>\n<\/li>\n<li>\n<p>\u042f\u043d\u0434\u0435\u043a\u0441 \u0418\u0433\u0440\u044b \u043f\u0440\u0438\u0441\u043b\u0430\u043b\u0438 SDK-\u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043f\u0430\u0443\u0437\u044b;<\/p>\n<\/li>\n<li>\n<p>\u043d\u0430\u0447\u0430\u043b\u0430\u0441\u044c \u0440\u0435\u043a\u043b\u0430\u043c\u0430;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043e\u0442\u043a\u0440\u044b\u043b \u0432\u043d\u0443\u0442\u0440\u0438\u0438\u0433\u0440\u043e\u0432\u043e\u0435 \u043c\u0435\u043d\u044e.<\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0441\u043b\u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u0436\u0434\u0443\u044e \u043f\u0440\u0438\u0447\u0438\u043d\u0443 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c <code>game.pause()<\/code>, \u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0443: \u0440\u0435\u043a\u043b\u0430\u043c\u0430 \u0443\u0436\u0435 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0430\u0441\u044c, \u043d\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0430 \u0432\u0441\u0451 \u0435\u0449\u0451 \u0441\u043a\u0440\u044b\u0442\u0430 \u2014 \u0430 \u0438\u0433\u0440\u0430 \u043f\u0440\u0435\u0436\u0434\u0435\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u043b\u0430\u0441\u044c.<\/p>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438\u0447\u0438\u043d\u044b \u043f\u0430\u0443\u0437\u044b \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 <code>Set<\/code>:<\/p>\n<pre><code>type PauseReason =  | 'visibility'  | 'focus'  | 'page'  | 'sdk'  | 'advertising'private readonly pauseReasons = new Set&lt;PauseReason&gt;()private addPauseReason(reason: PauseReason): void {  const wasPaused = this.pauseReasons.size &gt; 0  this.pauseReasons.add(reason)  if (wasPaused) {    return  }  this.eventBus.emit('platform:pause-requested', undefined)  void this.audio.suspend()}private removePauseReason(reason: PauseReason): void {  this.pauseReasons.delete(reason)  if (this.pauseReasons.size &gt; 0) {    return  }  this.eventBus.emit('platform:resume-requested', undefined)}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0418\u0433\u0440\u0430 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u043e\u0433\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u0438\u0441\u0447\u0435\u0437\u043b\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u043f\u0440\u0438\u0447\u0438\u043d\u0430 \u043f\u0430\u0443\u0437\u044b.<\/p>\n<p>\u0414\u043b\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0441\u0434\u0435\u043b\u0430\u043d \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0430\u0434\u0430\u043f\u0442\u0435\u0440. \u0418\u0433\u0440\u043e\u0432\u043e\u0439 \u043a\u043e\u0434 \u043d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 <code>YaGames.init()<\/code> \u0438 \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u0434\u0435\u0442\u0430\u043b\u0438 callback API \u0440\u0435\u043a\u043b\u0430\u043c\u044b. \u041e\u043d \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0432\u0440\u043e\u0434\u0435 <code>advertising:break-started<\/code> \u0438 <code>advertising:break-finished<\/code>.<\/p>\n<p>SDK-\u0430\u0434\u0430\u043f\u0442\u0435\u0440 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430:<\/p>\n<ul>\n<li>\n<p>\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e SDK;<\/p>\n<\/li>\n<li>\n<p><code>LoadingAPI.ready()<\/code>;<\/p>\n<\/li>\n<li>\n<p><code>GameplayAPI.start()<\/code> \u0438 <code>GameplayAPI.stop()<\/code>;<\/p>\n<\/li>\n<li>\n<p>fullscreen-\u0440\u0435\u043a\u043b\u0430\u043c\u0443;<\/p>\n<\/li>\n<li>\n<p>rewarded-\u0440\u0435\u043a\u043b\u0430\u043c\u0443;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043b\u0430\u0442\u0435\u0436\u0438, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b;<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0431\u044b\u0442\u0438\u044f <code>game_api_pause<\/code> \u0438 <code>game_api_resume<\/code>.<\/p>\n<\/li>\n<\/ul>\n<p>\u042d\u0442\u043e \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0438 \u0434\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438: \u043d\u0430 <code>localhost<\/code> \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0431\u0435\u0437 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0433\u043e SDK, \u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043a\u043e\u0434 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0442\u0435\u043c \u0436\u0435.<\/p>\n<h3>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u00ab\u0447\u0438\u0441\u0442\u043e\u0439\u00bb \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0438<\/h3>\n<p>Three.js-\u0441\u0446\u0435\u043d\u0443 \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u043a \u0436\u0435, \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e. \u041d\u043e \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b \u0438\u0433\u0440\u044b \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0438 WebGL.<\/p>\n<p>\u0412 Vitest \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u044e\u0442\u0441\u044f:<\/p>\n<ul>\n<li>\n<p>\u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b \u043c\u0435\u0436\u0434\u0443 \u0443\u0440\u043e\u0432\u043d\u044f\u043c\u0438;<\/p>\n<\/li>\n<li>\n<p>\u0432\u043e\u0437\u0432\u0440\u0430\u0442 \u043d\u0430 \u043d\u0443\u043b\u0435\u0432\u043e\u0439 \u0446\u0438\u043a\u043b \u043f\u043e\u0441\u043b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438;<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u0449\u0438\u0442\u0430 \u043e\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 \u0441 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u044b\u043c \u0447\u0438\u0441\u043b\u043e\u043c \u043f\u043e\u043f\u044b\u0442\u043e\u043a;<\/p>\n<\/li>\n<li>\n<p>\u0432\u044b\u0431\u043e\u0440 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u043e \u0432\u0435\u0441\u0430\u043c;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043f\u043e\u0432\u0442\u043e\u0440\u043e\u0432 \u0432 <code>ShuffleBag<\/code>;<\/p>\n<\/li>\n<li>\n<p>\u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0438 \u0441\u0431\u0440\u043e\u0441 \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0439;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u0430\u0443\u0437 \u0438 \u0440\u0435\u043a\u043b\u0430\u043c\u044b;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0430\u0434\u0430\u043f\u0442\u0435\u0440\u043e\u0432 \u042f\u043d\u0434\u0435\u043a\u0441 \u0418\u0433\u0440;<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0438 \u0447\u0442\u0435\u043d\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a.<\/p>\n<\/li>\n<\/ul>\n<p>\u0413\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 \u0441\u0435\u0441\u0441\u0438\u0438 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u0441\u0442\u0438 \u0447\u0435\u0440\u0435\u0437 dependency injection:<\/p>\n<pre><code>export interface GameSessionGeneratorOptions {  readonly anomalyPools: AnomalyPools  readonly random?: RandomSource}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412 \u0442\u0435\u0441\u0442\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0434\u0435\u0442\u0435\u0440\u043c\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439, \u043d\u0435 \u043d\u0430\u0434\u0435\u044f\u0441\u044c \u043d\u0430 \u0443\u0434\u0430\u0447\u0443 <code>Math.random()<\/code>.<\/p>\n<p>\u042d\u0442\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0432\u0430\u0436\u043d\u043e \u0434\u043b\u044f \u0438\u0433\u0440\u044b \u0441 \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e\u0441\u0442\u044f\u043c\u0438. \u0422\u0435\u0441\u0442 \u00ab\u043e\u0431\u044b\u0447\u043d\u043e \u0432\u044b\u043f\u0430\u0434\u0430\u0435\u0442 Easy\u00bb \u043f\u043e\u0447\u0442\u0438 \u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u0435\u043d. \u0413\u043e\u0440\u0430\u0437\u0434\u043e \u043b\u0443\u0447\u0448\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0447\u0442\u043e \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u0441\u0442\u0438 \u0432\u044b\u0431\u0440\u0430\u043d \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0438 \u0447\u0442\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043d\u0435 \u043d\u0430\u0440\u0443\u0448\u0430\u044e\u0442\u0441\u044f.<\/p>\n<h3>\u0427\u0442\u043e \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0441\u043b\u043e\u0436\u043d\u0435\u0435 \u0432\u0441\u0435\u0433\u043e<\/h3>\n<p>\u0421\u0430\u043c\u043e\u0439 \u043d\u0435\u043e\u0436\u0438\u0434\u0430\u043d\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u044c\u044e \u0431\u044b\u043b\u0430 \u043d\u0435 3D-\u0433\u0440\u0430\u0444\u0438\u043a\u0430.<\/p>\n<p>\u0421\u0446\u0435\u043d\u0443 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0437\u0430 \u0432\u0435\u0447\u0435\u0440. \u0414\u0432\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c. \u041a\u0430\u043c\u0435\u0440\u0443 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0434\u0432\u0438\u0433\u0430\u0442\u044c\u0441\u044f. \u041d\u043e \u043f\u043e\u0442\u043e\u043c \u0432\u044b\u044f\u0441\u043d\u044f\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0438\u0433\u0440\u0443 \u043d\u0443\u0436\u043d\u043e \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u0438 \u043f\u043e\u0442\u0435\u0440\u0435 \u0444\u043e\u043a\u0443\u0441\u0430, \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0437\u0432\u0443\u043a \u043f\u043e\u0441\u043b\u0435 \u0440\u0435\u043a\u043b\u0430\u043c\u044b, \u043d\u0435 \u0441\u043b\u043e\u043c\u0430\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0435, \u043e\u0441\u0432\u043e\u0431\u043e\u0434\u0438\u0442\u044c \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u0441\u0446\u0435\u043d\u044b, \u043f\u0435\u0440\u0435\u0436\u0438\u0442\u044c \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 SDK \u043d\u0430 localhost \u0438 \u043d\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0438\u0433\u0440\u043e\u043a\u0430 \u0432 \u0441\u0442\u0435\u043d\u0443 \u043f\u043e\u0441\u043b\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0438\u0437 \u0444\u043e\u043d\u043e\u0432\u043e\u0439 \u0432\u043a\u043b\u0430\u0434\u043a\u0438.<\/p>\n<p>\u0422\u043e \u0435\u0441\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0439 \u0438\u0433\u0440\u044b \u2014 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u043c\u0438\u0440, \u043d\u043e \u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0432\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u0441\u0440\u0435\u0434\u0443, \u0433\u0434\u0435 \u044d\u0442\u043e\u0442 \u043c\u0438\u0440 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u043c\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430.<\/p>\n<p>\u0412\u0442\u043e\u0440\u0430\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u2014 \u0433\u0440\u0430\u043d\u0438\u0446\u0430 \u043c\u0435\u0436\u0434\u0443 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u043e\u043c \u0438 \u043a\u043e\u0434\u043e\u043c. \u0415\u0441\u043b\u0438 \u043a\u0430\u0436\u0434\u0430\u044f \u043d\u043e\u0432\u0430\u044f \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u044f \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043c\u0435\u043d\u044f\u0442\u044c TypeScript, \u0437\u043d\u0430\u0447\u0438\u0442, \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 \u0435\u0449\u0451 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043e\u0442\u0434\u0435\u043b\u0435\u043d\u0430 \u043e\u0442 \u0434\u0432\u0438\u0436\u043a\u0430. \u041a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0438\u043c\u0451\u043d \u0438 \u0433\u0440\u0443\u043f\u043f \u0432 Blender \u0441\u0442\u0430\u043b \u043f\u0440\u043e\u0441\u0442\u044b\u043c, \u043d\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u043f\u0440\u043e\u0432\u0435\u0441\u0442\u0438 \u044d\u0442\u0443 \u0433\u0440\u0430\u043d\u0438\u0446\u0443.<\/p>\n<p>\u0422\u0440\u0435\u0442\u044c\u044f \u2014 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0433\u043e \u0438\u0433\u0440\u043e\u0432\u043e\u0433\u043e \u0434\u0432\u0438\u0436\u043a\u0430. \u042d\u0442\u043e \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u043c\u0438\u043d\u0443\u0441 \u0438 \u043f\u043b\u044e\u0441. \u041f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0441\u0430\u043c\u043e\u043c\u0443 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u043e \u0446\u0438\u043a\u043b\u0443, \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\u043c, \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c \u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u043c. \u0417\u0430\u0442\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u043b\u043e\u0439 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u043c \u0438 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c, \u0430 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0431\u043e\u043b\u044c\u0448\u043e\u0439 runtime-\u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u044b.<\/p>\n<h3>\u0427\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0432 \u0438\u0442\u043e\u0433\u0435<\/h3>\n<p>\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e Three.js-\u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f, \u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u0430\u044f \u0438\u0433\u0440\u0430 \u0441:<\/p>\n<ul>\n<li>\n<p>\u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c \u0438\u0433\u0440\u043e\u0432\u044b\u043c \u0441\u043b\u043e\u0435\u043c \u043f\u043e\u0432\u0435\u0440\u0445 Three.js;<\/p>\n<\/li>\n<li>\n<p>Vue-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c, \u043d\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438 3D-\u0441\u0446\u0435\u043d\u044b;<\/p>\n<\/li>\n<li>\n<p>\u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0448\u0438\u043d\u043e\u0439 \u0441\u043e\u0431\u044b\u0442\u0438\u0439;<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u043e\u0439 GLB \u0438 Draco-\u0434\u0435\u043a\u043e\u0434\u0435\u0440\u043e\u043c;<\/p>\n<\/li>\n<li>\n<p>\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u043c \u0441\u0446\u0435\u043d\u044b \u0438\u0437 Blender;<\/p>\n<\/li>\n<li>\n<p>\u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439 \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0439 \u0441 \u0443\u0440\u043e\u0432\u043d\u044f\u043c\u0438 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0431\u0440\u0430\u0442\u0438\u043c\u044b\u043c \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c \u0438 \u0441\u0431\u0440\u043e\u0441\u043e\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439;<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u043f\u0435\u0447\u0451\u043d\u043d\u044b\u043c \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u0435\u043c;<\/p>\n<\/li>\n<li>\n<p>PS1-\u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u043e\u043c \u0447\u0435\u0440\u0435\u0437 \u043d\u0438\u0437\u043a\u043e\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435, nearest-\u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044e, vertex snapping \u0438 dithering;<\/p>\n<\/li>\n<li>\n<p>\u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c;<\/p>\n<\/li>\n<li>\n<p>\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u0434\u043b\u044f \u0441\u043b\u0430\u0431\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432;<\/p>\n<\/li>\n<li>\n<p>\u0437\u0432\u0443\u043a\u043e\u043c \u0438 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 \u043f\u0430\u0443\u0437 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430, SDK \u0438 \u0440\u0435\u043a\u043b\u0430\u043c\u044b;<\/p>\n<\/li>\n<li>\n<p>\u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d\u043d\u044b\u0445 \u0430\u0434\u0430\u043f\u0442\u0435\u0440\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<p>\u041a\u043e\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043e\u0442\u043a\u0440\u044b\u0442 \u043d\u0430 GitHub. \u0418\u0433\u0440\u0443 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u044f\u043c\u043e \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/yandex.ru\/games\/app\/taproom-8-555243\" rel=\"noopener noreferrer nofollow\">Taproom 8 \u0432 \u042f\u043d\u0434\u0435\u043a\u0441 \u0418\u0433\u0440\u0430\u0445<\/a>;<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/StaburovAlexey\/Taproom8-anomaly\" rel=\"noopener noreferrer nofollow\">\u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u043d\u0430 GitHub<\/a>.<\/p>\n<\/li>\n<\/ul>\n<h3>\u0412\u043c\u0435\u0441\u0442\u043e \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f<\/h3>\n<p>\u042f \u043d\u0430\u0447\u0438\u043d\u0430\u043b \u0441 \u0436\u0435\u043b\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u043c\u043e\u0436\u043d\u043e \u043b\u0438 \u043d\u0430 \u0432\u0435\u0431-\u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f\u0445 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0443\u044e \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0443\u044e \u0438\u0433\u0440\u0443. \u0412 \u0438\u0442\u043e\u0433\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0443\u0437\u043d\u0430\u043b \u043d\u0435 \u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043c\u0435\u0448\u0435\u0439 \u0438 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432, \u0430 \u043e \u0433\u0440\u0430\u043d\u0438\u0446\u0430\u0445 \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043c\u0435\u0436\u0434\u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u043c\u0438.<\/p>\n<p>Three.js \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0442\u043e, \u0447\u0442\u043e\u0431\u044b \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435. \u041d\u043e \u0432\u0441\u0451 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u2014 \u0437\u0430\u0447\u0435\u043c \u044d\u0442\u043e \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c, \u043a\u043e\u0433\u0434\u0430 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0435\u0439, \u043a\u0430\u043a \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u0446\u0435\u043d\u0443, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u043f\u043e\u0441\u043b\u0435 \u0440\u0435\u043a\u043b\u0430\u043c\u044b \u0438 \u043a\u0430\u043a \u043d\u0435 \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0441\u043b\u0430\u0431\u044b\u0439 \u0442\u0435\u043b\u0435\u0444\u043e\u043d \u2014 \u0443\u0436\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0430\u043c\u043e\u043c\u0443.<\/p>\n<p>\u0418, \u043f\u043e\u0436\u0430\u043b\u0443\u0439, \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0441\u0430\u043c\u044b\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u043c.<\/p>\n<p>\u0422\u0435\u0433\u0438: gamedev, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0438\u0433\u0440, Three.js, WebGL, Vue.js, TypeScript, Blender, \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u0430\u044f \u0438\u0433\u0440\u0430, \u042f\u043d\u0434\u0435\u043a\u0441 \u0418\u0433\u0440\u044b, PS1, \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f<\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1069580\/\">https:\/\/habr.com\/ru\/articles\/1069580\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440.\u042f frontend-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0438 \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e \u0441 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430\u043c\u0438. \u0412 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043c\u043e\u043c\u0435\u043d\u0442 \u043c\u043d\u0435 \u0441\u0442\u0430\u043b\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043c\u043e\u0436\u043d\u043e \u043b\u0438 \u043d\u0430 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u043e\u043c \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u0432\u0435\u0431-\u0441\u0442\u0435\u043a\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435 \u0434\u0435\u043c\u043e \u0441 \u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u043c\u0441\u044f \u043a\u0443\u0431\u043e\u043c, \u0430 \u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d\u043d\u0443\u044e 3D-\u0438\u0433\u0440\u0443 \u2014 \u0441 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u043e\u0439 \u0441\u0446\u0435\u043d\u044b, \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c, \u0437\u0432\u0443\u043a\u043e\u043c, \u043c\u0435\u043d\u044e, \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0435\u0439 \u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0435\u0439 \u043d\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435.\u0422\u0430\u043a \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c Taproom 8 \u2014 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u0430\u044f \u0438\u0433\u0440\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043a\u0430\u0442\u044c \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0438 \u0432 \u043c\u0440\u0430\u0447\u043d\u043e\u043c \u0431\u0430\u0440\u0435.\u0418\u0433\u0440\u0430\u0442\u044c: Taproom 8 \u0432 \u042f\u043d\u0434\u0435\u043a\u0441 \u0418\u0433\u0440\u0430\u0445\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434: GitHub\u041d\u0438\u0436\u0435 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043d\u0435 \u0441\u0442\u043e\u043b\u044c\u043a\u043e \u043e \u0441\u0430\u043c\u043e\u0439 \u0438\u0433\u0440\u0435, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043e\u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0432\u043d\u0443\u0442\u0440\u0438.\u0421 \u0447\u0435\u0433\u043e \u0432\u0441\u0451 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c\u0421 Three.js \u044f \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043b\u0441\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 2D\/3D-\u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430. \u0422\u0430\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0431\u044b\u043b\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438 \u043d\u0430 \u0441\u0446\u0435\u043d\u0435: \u043a\u0430\u043c\u0435\u0440\u043e\u0439, \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0435\u0439, \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430\u043c\u0438 \u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u043c\u0438.\u0412 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043c\u043e\u043c\u0435\u043d\u0442 \u044f \u043f\u043e\u0439\u043c\u0430\u043b \u0441\u0435\u0431\u044f \u043d\u0430 \u043c\u044b\u0441\u043b\u0438: \u0435\u0441\u043b\u0438 \u044f \u0443\u0436\u0435 \u0443\u043c\u0435\u044e \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u0438, \u0434\u0432\u0438\u0433\u0430\u0442\u044c \u043a\u0430\u043c\u0435\u0440\u0443 \u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043f\u043e\u0447\u0435\u043c\u0443 \u0431\u044b \u043d\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u043f\u043e\u0432\u0435\u0440\u0445 \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0438\u0433\u0440\u0443?\u0418\u0434\u0435\u044f \u0434\u043b\u044f Taproom 8 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430\u0441\u044c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0439. \u0418\u0433\u0440\u043e\u043a \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u0432 \u043a\u043e\u043c\u043d\u0430\u0442\u0443 \u0438 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u0438\u0434\u0438\u0442 \u0435\u0451 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435. \u042d\u0442\u043e \u043d\u0443\u043b\u0435\u0432\u043e\u0439 \u0446\u0438\u043a\u043b, \u0432 \u043d\u0451\u043c \u043d\u0435\u0442 \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0439. \u041d\u0443\u0436\u043d\u043e \u0437\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c \u043f\u043e\u043c\u0435\u0449\u0435\u043d\u0438\u0435, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0446\u0438\u043a\u043b\u044b. \u0412 \u043a\u0430\u0436\u0434\u043e\u043c \u0438\u0437 \u043d\u0438\u0445 \u043c\u043e\u0436\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c\u0441\u044f \u043e\u0434\u0438\u043d \u043e\u0431\u044a\u0435\u043a\u0442: \u0438\u0441\u0447\u0435\u0437\u043d\u0443\u0442\u044c \u0441\u0442\u0443\u043b, \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u0430, \u043f\u043e\u044f\u0432\u0438\u0442\u044c\u0441\u044f \u0441\u0442\u0440\u0430\u043d\u043d\u044b\u0439 \u0441\u0438\u043b\u0443\u044d\u0442 \u0438\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c\u0441\u044f \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0434\u0432\u0435\u0440\u0438.\u0418\u0433\u0440\u043e\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043e\u0434\u043d\u0443 \u0438\u0437 \u0434\u0432\u0443\u0445 \u0434\u0432\u0435\u0440\u0435\u0439:\u00ab\u0415\u0441\u0442\u044c \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u044f\u00bb;\u00ab\u0410\u043d\u043e\u043c\u0430\u043b\u0438\u0439 \u043d\u0435\u0442\u00bb.\u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u043e\u0442\u0432\u0435\u0442 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u0442 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c, \u043e\u0448\u0438\u0431\u043a\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u043a \u043d\u0430\u0447\u0430\u043b\u0443.\u041d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0430 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0430\u044f. \u041d\u043e \u0432\u043e\u043a\u0440\u0443\u0433 \u043d\u0435\u0451 \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u043e\u044f\u0432\u0438\u043b\u0438\u0441\u044c \u0437\u0430\u0434\u0430\u0447\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435 \u0431\u044b\u043b\u043e \u0432 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u0435:\u043a\u0430\u043a \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0440\u0430\u0443\u043d\u0434\u0430;\u043a\u0430\u043a \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0438 \u0431\u0435\u0437 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u044f \u0438\u0433\u0440\u043e\u0432\u043e\u0433\u043e \u043a\u043e\u0434\u0430;\u043a\u0430\u043a \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043c\u0435\u0436\u0434\u0443 Vue \u0438 Three.js;\u043a\u0430\u043a \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0443\u044e GLB-\u0441\u0446\u0435\u043d\u0443;\u043a\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0442\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043f\u043e\u0434 PS1;\u043a\u0430\u043a \u043f\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u0432\u043a\u043b\u0430\u0434\u043a\u0438 \u0438 \u0440\u0435\u043a\u043b\u0430\u043c\u043d\u044b\u0435 \u043f\u0430\u0443\u0437\u044b;\u043a\u0430\u043a \u043d\u0435 \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0435\u043b\u0435\u0444\u043e\u043d \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u0432 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439 \u043e\u0431\u043e\u0433\u0440\u0435\u0432\u0430\u0442\u0435\u043b\u044c.\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0421\u0442\u0435\u043a \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0442\u0430\u043a\u0438\u043c:\u0422\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f\u0417\u043e\u043d\u0430 \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438Vue 3\u043c\u0435\u043d\u044e, \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438, HUD, \u044d\u043a\u0440\u0430\u043d\u044b \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044bTypeScript\u0438\u0433\u0440\u043e\u0432\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u044b \u043c\u0435\u0436\u0434\u0443 \u043f\u043e\u0434\u0441\u0438\u0441\u0442\u0435\u043c\u0430\u043c\u0438Three.js\u0441\u0446\u0435\u043d\u0430, \u043a\u0430\u043c\u0435\u0440\u0430, \u043c\u043e\u0434\u0435\u043b\u0438, \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u0438 WebGL-\u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433Vite\u0441\u0431\u043e\u0440\u043a\u0430 \u0438 dev-\u0441\u0435\u0440\u0432\u0435\u0440Pinia\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043avue-i18n\u0440\u0443\u0441\u0441\u043a\u0438\u0439 \u0438 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u0439 \u044f\u0437\u044b\u043a\u0438Vitest\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0438 \u0430\u0434\u0430\u043f\u0442\u0435\u0440\u043e\u0432\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u2014 \u043d\u0435 \u0441\u043c\u0435\u0448\u0438\u0432\u0430\u0442\u044c Vue-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0441 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438 3D-\u0441\u0446\u0435\u043d\u044b.\u0423\u0441\u043b\u043e\u0432\u043d\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u043e \u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u043e\u0451\u0432:Vue UI  \u2193 typed EventBusGameCoordinator \/ LifecycleCoordinator  \u2193Game \u2192 SceneManager \u2192 GameScene  \u2193Three.js: camera, player, level, input, interaction, rendererPlatform adapters \u2192 Yandex Games SDKVue \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441 \u00ab\u043a\u0430\u043a\u043e\u0439 \u044d\u043a\u0440\u0430\u043d \u0441\u0435\u0439\u0447\u0430\u0441 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u00bb. \u0418\u0433\u0440\u043e\u0432\u043e\u0439 \u0441\u043b\u043e\u0439 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441 \u00ab\u0447\u0442\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0442\u0438 \u0432 \u043c\u0438\u0440\u0435\u00bb.\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u043d\u043e\u043f\u043a\u0430 \u0432 UI \u043d\u0435 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0434\u0432\u0435\u0440\u044c \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0438 \u043d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043c\u0435\u0442\u043e\u0434\u044b Three.js. \u041e\u043d\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0432\u044b\u0431\u043e\u0440\u0430 \u0434\u0432\u0435\u0440\u0438. GameCoordinator \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0435\u0433\u043e, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0440\u0430\u0443\u043d\u0434\u0430 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043e\u0442\u0432\u0435\u0442\u0430.Three.js \u2014 \u044d\u0442\u043e \u043d\u0435 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0434\u0432\u0438\u0436\u043e\u043a\u042d\u0442\u043e \u0432\u0430\u0436\u043d\u043e\u0435 \u0443\u0442\u043e\u0447\u043d\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u044f \u0441\u0430\u043c \u043e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0441\u043e\u0437\u043d\u0430\u043b \u0443\u0436\u0435 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438.Three.js \u2014 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 3D-\u0433\u0440\u0430\u0444\u0438\u043a\u043e\u0439 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. \u041e\u043d\u0430 \u0434\u0430\u0451\u0442 \u0441\u0446\u0435\u043d\u0443, \u043a\u0430\u043c\u0435\u0440\u044b, \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u044e, \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b, \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b, \u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a\u0438 \u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0435\u0440. \u041d\u043e \u043e\u043d\u0430 \u043d\u0435 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0433\u043e\u0442\u043e\u0432\u0443\u044e \u0438\u0433\u0440\u043e\u0432\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u0443\u0440\u043e\u0432\u043d\u044f Unity \u0438\u043b\u0438 Unreal Engine.\u0412 Three.js \u043d\u0435\u0442 \u0433\u043e\u0442\u043e\u0432\u044b\u0445:\u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u0441\u0446\u0435\u043d \u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u0432 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438;\u0438\u0433\u0440\u043e\u0432\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 \u0441 \u043d\u0443\u0436\u043d\u044b\u043c\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c\u0438;\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430;\u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0439 \u0444\u0438\u0437\u0438\u043a\u0438 \u0438 \u043a\u043e\u043b\u043b\u0430\u0439\u0434\u0435\u0440\u043e\u0432;\u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0440\u0430\u0443\u043d\u0434\u043e\u0432 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0439;UI, \u043c\u0435\u043d\u044e \u0438 \u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439;\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u043e\u0439.\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0441\u043b\u043e\u0439. \u042d\u0442\u043e \u043d\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 Unity. \u041f\u0440\u043e\u0441\u0442\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443\u0437\u043a\u0438\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432, \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0440\u0435\u0448\u0430\u0435\u0442 \u043e\u0434\u043d\u0443 \u0437\u0430\u0434\u0430\u0447\u0443:Game \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u043c \u0446\u0438\u043a\u043b\u043e\u043c \u0438\u0433\u0440\u044b;Loop \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 requestAnimationFrame;SceneManager \u0445\u0440\u0430\u043d\u0438\u0442 \u0430\u043a\u0442\u0438\u0432\u043d\u0443\u044e \u0441\u0446\u0435\u043d\u0443;GameScene \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 \u0443\u0440\u043e\u0432\u0435\u043d\u044c, \u0438\u0433\u0440\u043e\u043a\u0430, \u0432\u0432\u043e\u0434, \u0437\u0432\u0443\u043a \u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f;Renderer \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 WebGL \u0438 PS1-\u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d;GameCoordinator \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u0435\u0441\u0441\u0438\u044f\u043c\u0438 \u0438 \u0440\u0430\u0443\u043d\u0434\u0430\u043c\u0438.\u0423 Game \u0435\u0441\u0442\u044c \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0446\u0438\u043a\u043b:export class Game {  private readonly loop: Loop  public constructor(\/* &#8230; *\/) {    this.loop = new Loop((deltaSeconds, elapsedSeconds) =&gt; {      this.update(deltaSeconds, elapsedSeconds)    })  }  private update(deltaSeconds: number, elapsedSeconds: number): void {    this.scenes.update(deltaSeconds, elapsedSeconds)    this.renderActiveScene()  }  private renderActiveScene(): void {    const scene = this.scenes.active    if (scene === null) {      return    }    this.renderer.render(scene.scene, scene.camera)  }}\u042d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u043e\u0441\u0442\u043e, \u043d\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a\u043e\u0439 \u0441\u043b\u043e\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0435 \u0440\u0430\u0437\u043d\u043e\u0441\u0438\u0442\u044c \u0432\u044b\u0437\u043e\u0432\u044b renderer.render, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043f\u0430\u0443\u0437\u044b \u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0441\u0446\u0435\u043d \u043f\u043e Vue-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c.\u0418\u0433\u0440\u043e\u0432\u043e\u0439 \u0446\u0438\u043a\u043b \u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u0430\u0443\u0437\u044b\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0441\u0430\u043c\u044b\u0439 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u0446\u0438\u043a\u043b. \u041f\u043e\u0442\u043e\u043c \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043b \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443: \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \u0432\u043a\u043b\u0430\u0434\u043a\u0443, \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0451\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u0434\u0440\u044b, \u0430 \u043f\u043e\u0441\u043b\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043e\u0433\u0440\u043e\u043c\u043d\u044b\u0439 deltaTime.\u0415\u0441\u043b\u0438 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0435\u0433\u043e \u0432 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0435 \u0438\u0433\u0440\u043e\u043a\u0430, \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436 \u043f\u043e\u0441\u043b\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0441\u0442\u0435\u043d\u0443.\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 Loop \u0435\u0441\u0442\u044c \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0448\u0430\u0433\u0430:export class Loop {  private readonly maxDeltaSeconds: number  private previousTimeMilliseconds = 0  private elapsedSeconds = 0  private animationFrameId: number | null = null  public constructor(    private readonly update: (delta: number, elapsed: number) =&gt; void,    options: { maxDeltaSeconds?: number } = {},  ) {    this.maxDeltaSeconds = options.maxDeltaSeconds ?? 0.1  }  private readonly tick = (timeMilliseconds: number): void =&gt; {    if (this.animationFrameId === null) {      return    }    const rawDelta = Math.max(      0,      (timeMilliseconds &#8212; this.previousTimeMilliseconds) \/ 1000,    )    const delta = Math.min(rawDelta, this.maxDeltaSeconds)    this.previousTimeMilliseconds = timeMilliseconds    this.elapsedSeconds += delta    this.update(delta, this.elapsedSeconds)    this.animationFrameId = requestAnimationFrame(this.tick)  }}\u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430\u043a\u0430\u043f\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f elapsedSeconds, \u0430 \u043f\u0440\u0438 \u043f\u0430\u0443\u0437\u0435 \u0446\u0438\u043a\u043b \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e. \u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 0.1 \u0441\u0435\u043a\u0443\u043d\u0434\u044b \u2014 \u044d\u0442\u043e \u0441\u0442\u0440\u0430\u0445\u043e\u0432\u043a\u0430, \u0430 \u043d\u0435 \u0437\u0430\u043c\u0435\u043d\u0430 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430.\u0422\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0448\u0438\u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439\u041c\u043d\u0435 \u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c, \u0447\u0442\u043e\u0431\u044b UI \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043b GameScene, \u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043a\u043e\u0434 \u043d\u0430\u0447\u0438\u043d\u0430\u043b \u0437\u043d\u0430\u0442\u044c \u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 Vue-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445. \u0414\u043b\u044f \u0441\u0432\u044f\u0437\u0438 \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439 \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 EventBus.\u0421\u043e\u0431\u044b\u0442\u0438\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u043e\u0434\u043d\u043e\u0439 \u043a\u0430\u0440\u0442\u043e\u0439:export interface GameEventMap {  &#8216;ui:graphics-changed&#8217;: {    readonly quality: &#8216;normal&#8217; | &#8216;potato&#8217;  }  &#8216;ui:mobile-move&#8217;: {    readonly x: number    readonly y: number  }  &#8216;interaction:door-selected&#8217;: {    readonly answer: boolean    readonly doorId: &#8216;anomaly&#8217; | &#8216;no-anomaly&#8217;    readonly objectName: &#8216;CorrectDoor&#8217; | &#8216;WrongDoor&#8217;  }  &#8217;round:started&#8217;: {    readonly level: number    readonly anomalyId: string | null    readonly hasAnomaly: boolean  }}\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e TypeScript \u043d\u0435 \u0434\u0430\u0441\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0441 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u043c payload:gameEventBus.emit(&#8216;interaction:door-selected&#8217;, {  answer: true,  doorId: &#8216;anomaly&#8217;,  objectName: &#8216;CorrectDoor&#8217;,})gameEventBus.on(&#8217;round:started&#8217;, (round) =&gt; {  console.log(round.level, round.anomalyId)})\u0418\u0433\u0440\u043e\u0432\u043e\u0439 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0432\u044b\u0431\u043e\u0440\u0430 \u0434\u0432\u0435\u0440\u0438:this.eventBus.on(  &#8216;interaction:door-selected&#8217;,  ({ answer }) =&gt; this.evaluateDoor(answer),)\u0414\u043b\u044f \u043c\u0435\u043d\u044f \u0437\u0434\u0435\u0441\u044c \u0432\u0430\u0436\u043d\u0430 \u043d\u0435 \u0441\u0430\u043c\u0430 \u0448\u0438\u043d\u0430, \u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438. UI \u0437\u043d\u0430\u0435\u0442 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0439. \u0418\u0433\u0440\u043e\u0432\u043e\u0439 \u0441\u043b\u043e\u0439 \u0437\u043d\u0430\u0435\u0442, \u0447\u0442\u043e \u044d\u0442\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043e\u0437\u043d\u0430\u0447\u0430\u044e\u0442. \u041d\u043e UI \u043d\u0435 \u0437\u043d\u0430\u0435\u0442, \u0432 \u043a\u0430\u043a\u043e\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u0435 Three.js \u043b\u0435\u0436\u0438\u0442 \u0434\u0432\u0435\u0440\u044c \u0438 \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0435\u0451 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f.\u0421\u0446\u0435\u043d\u0430 \u0438\u0437 Blender: \u0434\u043e\u0433\u043e\u0432\u043e\u0440 \u0432\u0430\u0436\u043d\u0435\u0435 \u043c\u0430\u0433\u0438\u0438\u0423\u0440\u043e\u0432\u0435\u043d\u044c \u0441\u043e\u0431\u0438\u0440\u0430\u043b\u0441\u044f \u0432 Blender \u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0441\u044f \u0432 level.glb. \u042f \u043d\u0435 \u0445\u043e\u0442\u0435\u043b \u0437\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 TypeScript. \u042d\u0442\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0432 \u043d\u0430\u0431\u043e\u0440 \u0447\u0438\u0441\u0435\u043b, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u043e \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c.\u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u0443 \u0441\u0446\u0435\u043d\u044b \u0435\u0441\u0442\u044c \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0451\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u0438 \u0438\u043c\u0435\u043d\u0430\u043c:Scene\u251c\u2500\u2500 StaticGeometry\u251c\u2500\u2500 Gameplay\u2502   \u251c\u2500\u2500 PlayerSpawn\u2502   \u251c\u2500\u2500 CorrectDoor\u2502   \u251c\u2500\u2500 WrongDoor\u2502   \u2514\u2500\u2500 AnomalyObjects\u251c\u2500\u2500 InteractiveDoors\u251c\u2500\u2500 Colliders\u2514\u2500\u2500 Lights\u041f\u0440\u0438\u043c\u0435\u0440 \u0433\u0440\u0443\u043f\u043f\u044b \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0439:AnomalyObjects\u251c\u2500\u2500 FlipFlopObj\u2502   \u251c\u2500\u2500 CHAIR_easy\u2502   \u251c\u2500\u2500 LAMP_medium\u2502   \u2514\u2500\u2500 BOTTLE_hard\u251c\u2500\u2500 FlipTextureObj\u2502   \u251c\u2500\u2500 Painting01_easy\u2502   \u2514\u2500\u2500 Sign01_hard\u2514\u2500\u2500 SpriteAnomalyPoints    \u251c\u2500\u2500 Hallway_easy    \u2514\u2500\u2500 Doorway_hard\u0421\u0443\u0444\u0444\u0438\u043a\u0441 \u0432 \u0438\u043c\u0435\u043d\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u2014 \u044d\u0442\u043e \u043d\u0435 \u0447\u0430\u0441\u0442\u044c \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0432 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u043c \u0441\u043c\u044b\u0441\u043b\u0435. \u042d\u0442\u043e \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439 DSL \u0443\u0440\u043e\u0432\u043d\u044f:_easy \u2014 \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u044f;_medium \u2014 \u0441\u0440\u0435\u0434\u043d\u044f\u044f;_hard \u2014 \u0441\u043b\u043e\u0436\u043d\u0430\u044f.\u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:\u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438\u043b\u0438 \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 Blender;\u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u043d\u0443\u0436\u043d\u0443\u044e \u0433\u0440\u0443\u043f\u043f\u0443;\u043d\u0430\u0437\u0432\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u043c \u0441\u0443\u0444\u0444\u0438\u043a\u0441\u043e\u043c;\u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c GLB.\u0412 \u043a\u043e\u0434\u0435 \u043d\u0435 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0439 if \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u0442\u0443\u043b\u0430 \u0438\u043b\u0438 \u043a\u0430\u0440\u0442\u0438\u043d\u044b.\u041a\u0430\u043a \u0434\u0432\u0438\u0436\u043e\u043a \u043d\u0430\u0445\u043e\u0434\u0438\u0442 \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u0438\u041f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 GLB \u0434\u0432\u0438\u0436\u043e\u043a \u0441\u043a\u0430\u043d\u0438\u0440\u0443\u0435\u0442 \u043f\u0440\u044f\u043c\u044b\u0445 \u0434\u0435\u0442\u0435\u0439 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u0433\u0440\u0443\u043f\u043f \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0438\u0445 \u0438\u043c\u0435\u043d\u0430:const DIFFICULTY_BY_SUFFIX = {  easy: &#8216;Easy&#8217;,  medium: &#8216;Medium&#8217;,  hard: &#8216;Hard&#8217;,} as constfunction parseDefinition(  object: Object3D,  kind: LevelAnomalyKind,): LevelAnomalyDefinition | string {  const match = \/_(easy|medium|hard)$\/i.exec(object.name)  if (match === null) {    return `Object &#171;${object.name}&#187; has no difficulty suffix.`  }  const suffix = match[1].toLowerCase()  const difficulty = DIFFICULTY_BY_SUFFIX[suffix]  const assetBaseName = object.name.slice(0, match.index).trim()  return {    kind,    difficulty,    targetObjectId: object.name,    assetBaseName,  }}\u0415\u0441\u043b\u0438 \u043e\u0431\u044a\u0435\u043a\u0442 \u043d\u0430\u0437\u0432\u0430\u043d \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e, \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0430\u0434\u0430\u0435\u0442 \u0446\u0435\u043b\u0438\u043a\u043e\u043c. \u0414\u0432\u0438\u0436\u043e\u043a \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 recoverable error, \u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0430\u044f \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u0430\u044f \u0430\u043d\u043e\u043c\u0430\u043b\u0438\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0438\u0437 \u043f\u0443\u043b\u043e\u0432. \u042d\u0442\u043e \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u0435\u0435, \u0447\u0435\u043c \u0431\u0435\u043b\u044b\u0439 \u044d\u043a\u0440\u0430\u043d \u0438\u0437-\u0437\u0430 \u043e\u0434\u043d\u043e\u0439 \u043e\u043f\u0435\u0447\u0430\u0442\u043a\u0438 \u0432 Blender.\u041e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u0435: \u0432 production-\u0441\u0446\u0435\u043d\u0435 \u043d\u0435\u0442 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u0441\u0432\u0435\u0442\u0430\u0412 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u0446\u0435\u043d\u0435 \u044f \u043f\u043e\u0448\u0451\u043b \u043f\u043e \u043f\u0443\u0442\u0438 \u0437\u0430\u043f\u0435\u0447\u0451\u043d\u043d\u043e\u0433\u043e \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u044f. \u0412 level.glb \u043d\u0435\u0442 \u0440\u0430\u0431\u043e\u0447\u0438\u0445 PointLight, SpotLight \u0438\u043b\u0438 DirectionalLight. \u0413\u0440\u0443\u043f\u043f\u0430 Lights \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0441\u0446\u0435\u043d\u044b, \u043d\u043e \u0441\u0430\u043c\u0430 production-\u0441\u0446\u0435\u043d\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u044e \u0438 \u0443\u0436\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b.\u041d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 Three.js \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0435 \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0435\u043d\u0438:this.instance = new WebGLRenderer({  antialias: false,  powerPreference: &#8216;high-performance&#8217;,})this.instance.shadowMap.enabled = false\u0414\u043b\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u0441 \u0443\u0436\u0435 \u0437\u0430\u043f\u0435\u0447\u0451\u043d\u043d\u044b\u043c\u0438 \u0441\u0432\u0435\u0442\u043e\u043c \u0438 \u0442\u0435\u043d\u044f\u043c\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-490652","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/490652","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=490652"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/490652\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=490652"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=490652"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=490652"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}