{"id":12476,"date":"2025-12-17T17:17:58","date_gmt":"2025-12-17T08:17:58","guid":{"rendered":"https:\/\/media.value-domain.com\/?p=12476"},"modified":"2025-12-18T12:18:55","modified_gmt":"2025-12-18T03:18:55","slug":"webbase3d","status":"publish","type":"post","link":"https:\/\/media.value-domain.com\/webbase3d\/","title":{"rendered":"\u3010Three.js\u5165\u9580\u3011Web\u30d6\u30e9\u30a6\u30b6\u3067\u52d5\u304f\u7c21\u66133D\u90e8\u5c4b\u30ec\u30a4\u30a2\u30a6\u30c8\u30c4\u30fc\u30eb\u3092\u4f5c\u308d\u3046\uff01"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"632\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/thumb_webbase3d-1024x632.png\" alt=\"\u3010Three.js\u5165\u9580\u3011W\u7c21\u66133D\u90e8\u5c4b\u30ec\u30a4\u30a2\u30a6\u30c8\u30c4\u30fc\u30eb\u4f5c\u6210\" class=\"wp-image-12526\" srcset=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/thumb_webbase3d-1024x632.png 1024w, https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/thumb_webbase3d-300x185.png 300w, https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/thumb_webbase3d-768x474.png 768w, https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/thumb_webbase3d-530x327.png 530w, https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/thumb_webbase3d-565x349.png 565w, https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/thumb_webbase3d-710x439.png 710w, https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/thumb_webbase3d-725x448.png 725w, https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/thumb_webbase3d.png 1360w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">\u306f\u3058\u3081\u306b<\/h2>\n\n\n\n<p>\u5bb6\u5177\u306e\u914d\u7f6e\u3092\u8003\u3048\u305f\u3044\u3001\u65b0\u3057\u3044\u30aa\u30d5\u30a3\u30b9\u306e\u30ec\u30a4\u30a2\u30a6\u30c8\u3092\u8a08\u753b\u3057\u305f\u3044\u3001\u3042\u308b\u3044\u306f\u30b2\u30fc\u30e0\u306e\u30b9\u30c6\u30fc\u30b8\u3092\u4f5c\u3063\u3066\u307f\u305f\u3044\u3002\u305d\u3093\u306a\u3068\u304d\u3001\u982d\u306e\u4e2d\u306e\u30a4\u30e1\u30fc\u30b8\u3092\u5b9f\u969b\u306b\u300c\u898b\u3048\u308b\u5316\u300d\u3067\u304d\u305f\u3089\u4fbf\u5229\u3060\u3068\u601d\u3044\u307e\u305b\u3093\u304b\uff1f<br>\u305d\u3046\u3044\u3063\u305f\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306f\u6ca2\u5c71\u30ea\u30ea\u30fc\u30b9\u3055\u308c\u3066\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u3053\u308c\u307e\u30673D\u30b3\u30f3\u30c6\u30f3\u30c4\u3092\u4f5c\u6210\u3059\u308b\u306b\u306f\u3001\u5c02\u9580\u7684\u306a\u30bd\u30d5\u30c8\u30a6\u30a7\u30a2\u3068\u5b66\u7fd2\u30b3\u30b9\u30c8\u304c\u5fc5\u8981\u3067\u3057\u305f\u3002\u3057\u304b\u3057\u4eca\u3001Web\u30d6\u30e9\u30a6\u30b6\u3068\u3044\u3046\u8ab0\u3082\u304c\u6301\u3063\u3066\u3044\u308b\u30c4\u30fc\u30eb\u3060\u3051\u3067\u3001\u30a4\u30f3\u30bf\u30e9\u30af\u30c6\u30a3\u30d6\u306a3D\u4e16\u754c\u3092\u4f5c\u308a\u51fa\u305b\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u3053\u306e\u8a18\u4e8b\u3067\u306f\u3001<strong>Three.js\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u7248\uff08three.module.js\uff09<\/strong>\u3092\u4f7f\u3063\u305fWeb\u30d6\u30e9\u30a6\u30b6\u4e0a\u3067\u52d5\u4f5c\u3059\u308b\u7c21\u66133D\u30ec\u30a4\u30a2\u30a6\u30c8\u30c4\u30fc\u30eb\u306e\u958b\u767a\u3092\u884c\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<p>3D\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u4f5c\u6210\u304c\u521d\u3081\u3066\u306e\u65b9\u3067\u3082\u7406\u89e3\u3067\u304d\u308b\u3088\u3046\u306b\u3001\u4e00\u6b69\u305a\u3064\u4e01\u5be7\u306b\u9032\u3081\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u3053\u306e\u8a18\u4e8b\u306f\u4e0b\u8a18\u306e\u30e6\u30fc\u30b6\u30fc\u306b\u6700\u9069\u306a\u3082\u306e\u3067\u3059\u3002<\/p>\n\n\n\n<div class=\"wp-block-luxe-blocks-border-block\" style=\"margin-top:10px;margin-bottom:30px\"><div class=\"wp-block-luxe-blocks-border-block-content\" style=\"border:1px solid #006edc;border-radius:0px;padding:0px 15px 0px 15px\">\n<ul>\n<li>JavaScript\u306e\u57fa\u672c\u7684\u306a\u77e5\u8b58\u304c\u3042\u308a\u3001\u6b21\u306b\u4f55\u3092\u5b66\u3076\u304b\u63a2\u3057\u3066\u3044\u308b\u65b9\u3002<\/li>\n\n\n\n<li>Web\u30d6\u30e9\u30a6\u30b6\u3067\u52d5\u304f\u30ea\u30c3\u30c1\u306a\u30b3\u30f3\u30c6\u30f3\u30c4\u306e\u958b\u767a\u306b\u8208\u5473\u304c\u3042\u308b\u65b9\u3002<\/li>\n\n\n\n<li>Three.js\u3092\u4f7f\u3063\u305f3D\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0\u306e\u57fa\u790e\u3092\u30bc\u30ed\u304b\u3089\u5b66\u3073\u305f\u3044\u65b9\u3002<\/li>\n<\/ul>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-luxe-blocks-topic\" style=\"margin-top:10px;margin-bottom:30px\"><div class=\"wp-block-luxe-blocks-topic-title\" style=\"color:#fff;background-color:#006edc;border:1px solid #006edc;padding:2px 14px;align-items:center\">\u672c\u8a18\u4e8b\u3067\u4f5c\u6210\u3059\u308b3D\u30ec\u30a4\u30a2\u30a6\u30c8\u30c4\u30fc\u30eb\u306e\u6a5f\u80fd<\/div><div class=\"wp-block-luxe-blocks-topic-content\" style=\"border:1px solid #006edc;padding:0px 15px 0px 15px\">\n\n<ul>\n\n<li>3D\u7a7a\u9593\uff08\u90e8\u5c4b\u3084\u30aa\u30d5\u30a3\u30b9\u30d5\u30ed\u30a2\uff09\u306e\u69cb\u7bc9\u3002<\/li>\n\n\n<li>\u673a\u3001\u6905\u5b50\u3001\u30ad\u30e3\u30d3\u30cd\u30c3\u30c8\u306a\u3069\u306e\u5bb6\u5177\uff083D\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\uff09\u306e\u914d\u7f6e\u3002<\/li>\n\n\n<li>Blender\u306a\u3069\u3067\u4f5c\u6210\u3057\u305f3D\u30e2\u30c7\u30eb\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u3093\u3067\u914d\u7f6e\u3002<\/li>\n\n\n<li>\u914d\u7f6e\u3057\u305f\u5bb6\u5177\u3092\u30c9\u30e9\u30c3\u30b0\uff06\u30c9\u30ed\u30c3\u30d7\u3067\u79fb\u52d5\u30fb\u56de\u8ee2\u3055\u305b\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/li>\n\n\n<li>\u4f5c\u6210\u3057\u305f\u30ec\u30a4\u30a2\u30a6\u30c8\u3092\u69d8\u3005\u306a\u89d2\u5ea6\u304b\u3089\u81ea\u7531\u306b\u898b\u56de\u3059\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/li>\n\n<\/ul>\n\n<\/div><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Three.js\u3068\u30e2\u30b8\u30e5\u30fc\u30eb\u5f62\u5f0f\uff1a\u3044\u307e\u3069\u304d\u306e3D\u958b\u767a<\/h2>\n\n\n\n<p>Three.js\u306fWebGL\u3092\u7c21\u5358\u306b\u6271\u3048\u308b\u3088\u3046\u306b\u3057\u305fJavaScript\u30e9\u30a4\u30d6\u30e9\u30ea\u3067\u3059\u304c\u3001\u4eca\u56de\u306fES<strong>\u30e2\u30b8\u30e5\u30fc\u30eb\u5f62\u5f0f<\/strong>\u3092\u4f7f\u7528\u3057\u307e\u3059\u3002\u3053\u308c\u306fJavaScript\u958b\u767a\u3067\u6a19\u6e96\u7684\u306b\u4f7f\u308f\u308c\u3066\u3044\u308b\u65b9\u6cd5\u3067\u5fc5\u8981\u306a\u6a5f\u80fd\u3060\u3051\u3092\u52b9\u7387\u7684\u306b\u8aad\u307f\u8fbc\u3081\u307e\u3059\u3002\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u6574\u7406\u304c\u3057\u3084\u3059\u304f\u3001\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3082\u512a\u308c\u3066\u3044\u308b\u306e\u304c\u7279\u9577\u3067\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u4f7f\u7528\u3059\u308b\u4e3b\u8981\u6280\u8853<\/h3>\n\n\n\n<p>\u672c\u30c4\u30fc\u30eb\u306f\u3001\u73fe\u4ee3\u306eWeb\u958b\u767a\u3067\u5e83\u304f\u5229\u7528\u3055\u308c\u3066\u3044\u308b\u6280\u8853\u3092\u30d9\u30fc\u30b9\u306b\u69cb\u7bc9\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<figure class=\"wp-block-table scroll\"><table><thead><tr><th>\u6280\u8853<\/th><th>\u5f79\u5272<\/th><th>\u5185\u5bb9<\/th><\/tr><\/thead><tbody><tr><td>HTML\/CSS<\/td><td>WEB\u69cb\u9020\u3068\u30b9\u30bf\u30a4\u30eb<\/td><td>3D\u30ad\u30e3\u30f3\u30d0\u30b9\u3092\u914d\u7f6e\u3057\u3001UI\u8981\u7d20\uff08\u30dc\u30bf\u30f3\u306a\u3069\uff09\u3092\u88c5\u98fe\u3059\u308b\u57fa\u790e\u3068\u306a\u308a\u307e\u3059\u3002<\/td><\/tr><tr><td>JavaScript<\/td><td>\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0\u8a00\u8a9e<\/td><td>3D\u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u5236\u5fa1\u3057\u3001\u30e6\u30fc\u30b6\u30fc\u64cd\u4f5c\uff08\u30de\u30a6\u30b9\u30a4\u30d9\u30f3\u30c8\uff09\u3092\u51e6\u7406\u3059\u308b\u6838\u3068\u306a\u308a\u307e\u3059\u3002<\/td><\/tr><tr><td>Three.js<br>(three.module.js\uff09<\/td><td>3D\u30b0\u30e9\u30d5\u30a3\u30c3\u30af\u30e9\u30a4\u30d6\u30e9\u30ea<\/td><td>WebGL\u306e\u8907\u96d1\u306a\u51e6\u7406\u3092\u62bd\u8c61\u5316\u3057\u3001JavaScript\u304b\u3089\u7c21\u5358\u306b3D\u30b7\u30fc\u30f3\u3092\u4f5c\u6210\u30fb\u64cd\u4f5c\u3067\u304d\u308b\u3088\u3046\u306b\u3059\u308b\u305f\u3081\u306e\u4e3b\u5f79\u3067\u3059\u3002<\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\">Web\u958b\u767a\u3067\u5229\u7528\u3059\u308b\u6280\u8853\u4e00\u89a7<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">\u958b\u767a\u74b0\u5883\u306e\u6e96\u5099<\/h2>\n\n\n\n<div class=\"wp-block-luxe-blocks-topic\" style=\"margin-top:10px;margin-bottom:30px\"><div class=\"wp-block-luxe-blocks-topic-title\" style=\"color:#fff;background-color:#006edc;border:1px solid #006edc;padding:2px 14px;align-items:center\">\u3053\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306b\u6311\u6226\u3059\u308b\u305f\u3081\u306b\u5fc5\u8981\u306a\u3082\u306e<\/div><div class=\"wp-block-luxe-blocks-topic-content\" style=\"border:1px solid #006edc;padding:0px 15px 0px 15px\">\n\n<ul type=\"1\">\n\n<li><strong>\u30d1\u30bd\u30b3\u30f3<\/strong>  - Windows\u3001Mac\u3001Linux\u3069\u308c\u3067\u3082\u53ef\u3002<\/li>\n\n\n<li><strong>Web<\/strong><strong>\u30d6\u30e9\u30a6\u30b6<\/strong> - Chrome\u3001Firefox\u3001Safari\u306a\u3069\u3002<\/li>\n\n\n<li><strong>\u30c6\u30ad\u30b9\u30c8\u30a8\u30c7\u30a3\u30bf<\/strong> - \u30e2\u30b8\u30e5\u30fc\u30eb\u958b\u767a\u306b\u5bfe\u5fdc\u3057\u305f\u30a8\u30c7\u30a3\u30bf\u3068\u3057\u3066\u3001Visual Studio Code\uff08VS Code\uff09\u3092\u4f7f\u7528\u3057\u307e\u3059\u3002<\/li>\n\n\n<li><strong>\u30ed\u30fc\u30ab\u30eb\u30b5\u30fc\u30d0\u30fc\u74b0\u5883<\/strong> - VS Code\u3067\u5229\u7528\u3067\u304d\u308b\u300cLive Server\u300d\u62e1\u5f35\u6a5f\u80fd\u3092\u4f7f\u7528\u3057\u307e\u3059\u3002<\/li>\n\n<\/ul>\n\n<\/div><\/div>\n\n\n\n<p><strong>\u203b\u6ce8\u610f\u70b9<\/strong>\uff1athree.module.js\u3092\u4f7f\u7528\u3059\u308b\u306b\u306f\u3001\u30ed\u30fc\u30ab\u30eb\u30b5\u30fc\u30d0\u30fc\u74b0\u5883\u304c\u5fc5\u8981\u3067\u3059\u3002\u3053\u308c\u306f\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u4e0a\u306e\u5236\u7d04\u306b\u3088\u308b\u3082\u306e\u3067\u3001\u30d5\u30a1\u30a4\u30eb\u3092\u76f4\u63a5\u958b\u304f\uff08file:\/\/\u5bfe\u8c61\u30d5\u30a1\u30a4\u30eb\uff09\u3053\u3068\u3067\u306f\u52d5\u4f5c\u3057\u307e\u305b\u3093\u3002\u3067\u3082\u5fc3\u914d\u3042\u308a\u307e\u305b\u3093\uff01VS Code\u306e\u300cLive Server\u300d\u62e1\u5f35\u6a5f\u80fd\u3092\u5229\u7528\u3059\u308c\u3070\u7c21\u5358\u306b\u958b\u767a\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<p>Web\u30b5\u30fc\u30d0\u30fc\u304c\u3042\u308c\u3070\u3001\u30db\u30fc\u30e0\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306b\u76f4\u63a5\u4f5c\u6210\u3057\u305f\u30d5\u30a1\u30a4\u30eb\u3092\u914d\u7f6e\u3059\u308c\u3070\u3001\u30d6\u30e9\u30a6\u30b6\u3067URL\u306b\u30a2\u30af\u30bb\u30b9\u3057\u3066\u3082\u52d5\u4f5c\u3057\u307e\u3059\u3002<br>Web\u30b5\u30fc\u30d0\u30fc\u3067\u8a66\u3059\u306e\u3067\u3042\u308c\u3070GMO DigiRock\u304c\u63d0\u4f9b\u3057\u3066\u3044\u308b<a id=\"vn_cta_lp_xrea\" class=\"ga_event_link\" style=\"{style}\" href=\"https:\/\/www.xrea.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">\u7121\u6599\u30ec\u30f3\u30bf\u30eb\u30b5\u30fc\u30d0\u30fcXREA<\/a>\u304c\u3042\u308a\u307e\u3059\u306e\u3067\u5229\u7528\u3057\u3066\u307f\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n\n\n\n<div class=\"wp-block-luxe-blocks-topic\" style=\"margin-top:10px;margin-bottom:30px\"><div class=\"wp-block-luxe-blocks-topic-title\" style=\"color:#fff;background-color:#006edc;border:1px solid #006edc;padding:2px 14px;align-items:center\">XREA\u3092\u5229\u7528\u3059\u308b\u30e1\u30ea\u30c3\u30c8<\/div><div class=\"wp-block-luxe-blocks-topic-content\" style=\"border:1px solid #006edc;padding:0px 15px 0px 15px\">\n\n<p><strong>\u5b8c\u5168\u7121\u6599\u30d7\u30e9\u30f3\u3042\u308a<\/strong>\uff1a\u521d\u671f\u8cbb\u7528\u30fb\u6708\u984d\u8cbb\u75280\u5186<br><strong>\u958b\u767a\u3068\u516c\u958b\u3092\u540c\u6642\u306b<\/strong>\uff1a\u30ed\u30fc\u30ab\u30eb\u958b\u767a\u306e\u624b\u9593\u3092\u7701\u304d\u3001\u5b9f\u74b0\u5883\u3067\u30c6\u30b9\u30c8\u53ef\u80fd<br><strong>SSL\u5bfe\u5fdc\u3067\u5b89\u5fc3<\/strong>\uff1ahttps:\/\/\u3067\u306e\u5b89\u5168\u306a\u30a2\u30af\u30bb\u30b9<br><strong>\u5b8c\u6210\u5f8c\u3059\u3050\u516c\u958b<\/strong>\uff1a\u53cb\u4eba\u3084\u540c\u50da\u3068URL\u5171\u6709\u3060\u3051\u3067\u4f5c\u54c1\u3092\u898b\u305b\u3089\u308c\u308b<br><strong>\u30dd\u30fc\u30c8\u30d5\u30a9\u30ea\u30aa\u306b\u6700\u9069<\/strong>\uff1a\u5c31\u8077\u6d3b\u52d5\u3067\u306e\u5b9f\u7e3e\u30a2\u30d4\u30fc\u30eb\u306b\u3082\u6d3b\u7528\u53ef\u80fd<\/p>\n\n<\/div><\/div>\n\n\n\n<p>\u4f5c\u6210\u3057\u305f\u30d5\u30a1\u30a4\u30eb\u3092\u305d\u306e\u307e\u307e\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3059\u308b\u3060\u3051\u3067\u3001\u3042\u306a\u305f\u306e3D\u30c4\u30fc\u30eb\u304c\u4e16\u754c\u4e2d\u304b\u3089\u30a2\u30af\u30bb\u30b9\u53ef\u80fd\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<div class=\"wp-block-buttons\"><div class=\"wp-block-button has-custom-width wp-block-button__width-100 btn-service xrea\">\n<p class=\"txt\">\u7121\u6599\u30ec\u30f3\u30bf\u30eb\u30b5\u30fc\u30d0\u30fc<\/p>\n<a id=\"vn_cta_btn_lp_xrea\" class=\"ga_event_link wp-block-button__link has-white-color\" href=\"https:\/\/www.xrea.com\/\" style=\"background-color:#0d3978\" target=\"_blank\" rel=\"noreferrer noopener\">XREA\u516c\u5f0f\u30b5\u30a4\u30c8\u3092\u307f\u308b<\/a><\/div><\/div>\n\n\n\n<p>\u4eca\u56de\u3001\u958b\u767a\u3092\u9032\u3081\u3066\u3044\u304f\u306b\u3042\u305f\u308a\u30de\u30a4\u30af\u30ed\u30bd\u30d5\u30c8\u306eVS Code\u3092\u5229\u7528\u3057\u307e\u3059\u3002\u65e2\u306b\u4f7f\u3063\u3066\u3044\u308b\u65b9\u306fVS Code\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3092\u98db\u3070\u3057\u3066\u6b21\u306b\u9032\u3093\u3067\u304f\u3060\u3055\u3044\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">VS Code\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb<\/h3>\n\n\n\n<p><span style=\"font-weight:bold\">\u30fbVisual Studio Code\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30e9\u30fc\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3059\u308b<\/span><br><a rel=\"noreferrer noopener\" href=\"https:\/\/code.visualstudio.com\/download\" target=\"_blank\">https:\/\/code.visualstudio.com\/download<\/a>\u304b\u3089\u30d1\u30bd\u30b3\u30f3\u306eOS\u306b\u5408\u3063\u305f\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002<br>\u672c\u8a18\u4e8b\u3067\u306fWindows\u74b0\u5883\u3067\u69cb\u7bc9\u3057\u3066\u3044\u307e\u3059\u3002\u3053\u306e\u5834\u5408\u306f\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u753b\u9762\u4e2d\u304b\u3089Windows\u306e\u30ed\u30b4\u30de\u30fc\u30af\u3092\u30af\u30ea\u30c3\u30af\u3057\u3066\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3057\u3001\u30c7\u30d5\u30a9\u30eb\u30c8\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3092\u3057\u3066\u304f\u3060\u3055\u3044\u3002<br><img decoding=\"async\" class=\"wp-image-49878\" style=\"width: 640px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-31.png\" alt=\"VS Code\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\"><br><\/p>\n\n\n\n<p><span style=\"font-weight:bold\">\u30fb\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u5f8c\u3001VS Code\u3092\u8d77\u52d5<\/span><br>\u62e1\u5f35\u6a5f\u80fd\u30a2\u30a4\u30b3\u30f3\u3092\u30af\u30ea\u30c3\u30af\u3057\u3066\u4ee5\u4e0b\u306e\uff13\u3064\u3092\u691c\u7d22\u3057\u3066\u305d\u308c\u305e\u308c\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n\n\n\n<ul type=\"1\">\n<li><strong>Live Server<\/strong>\u3000\uff08<strong>\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u5fc5\u9808<\/strong>\u3001\u30ed\u30fc\u30ab\u30eb\u30b5\u30fc\u30d0\u30fc\u74b0\u5883\u3067\u3059\u3002\uff09<\/li>\n\n\n\n<li><strong>Live Preview<\/strong>\uff08\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u63a8\u5968\u3001VS Code\u5185\u306e\u753b\u9762\u3067\u30d6\u30e9\u30a6\u30b8\u30f3\u30b0\u7d50\u679c\u304c\u30ea\u30a2\u30eb\u30bf\u30a4\u30e0\u3067\u8868\u793a\u3067\u304d\u307e\u3059\u3002\uff09<\/li>\n\n\n\n<li><strong>Japanese Language Pack for VS Code<\/strong>\uff08\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u63a8\u5968\u3001\u65e5\u672c\u8a9e\u30d1\u30c3\u30b1\u30fc\u30b8\u3067\u3059\u3002\uff09<\/li>\n<\/ul>\n\n\n\n<p><img decoding=\"async\" class=\"wp-image-49195\" style=\"width: 480px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-2.png\" alt=\"VS Code\u62e1\u5f35\u30e9\u30a4\u30d6\u30e9\u30ea\u9078\u629e\"><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u958b\u767a\u306b\u5fc5\u8981\u306a\u30d5\u30a1\u30a4\u30eb\u69cb\u6210<\/h3>\n\n\n\n<p>\u672c\u30c4\u30fc\u30eb\u306f\u3001\u73fe\u4ee3\u306eWeb\u958b\u767a\u3067\u5e83\u304f\u5229\u7528\u3055\u308c\u3066\u3044\u308b\u6280\u8853\u3092\u30d9\u30fc\u30b9\u306b\u69cb\u7bc9\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<figure class=\"wp-block-table scroll\"><table><thead><tr><th>\u30d5\u30a1\u30a4\u30eb\u540d<\/th><th>\u5f79\u5272<\/th><th>\u5185\u5bb9<\/th><\/tr><\/thead><tbody><tr><td>index.html<\/td><td>Web\u69cb\u9020<\/td><td><strong>\u65b0\u898f\u4f5c\u6210<\/strong><br>importmap\u3092\u5229\u7528\u3057\u3066\u3001three.module.js\u3092\u30ed\u30fc\u30c9\u3057\u3066\u304a\u304d\u307e\u3059\u3002\u30dc\u30bf\u30f3\u306e\u914d\u7f6e<\/td><\/tr><tr><td>style.css<\/td><td>\u30b9\u30bf\u30a4\u30eb<\/td><td><strong>\u65b0\u898f\u4f5c\u6210<\/strong><br>Web\u30da\u30fc\u30b8\u5168\u4f53\u3001\u7279\u306b3D\u30ad\u30e3\u30f3\u30d0\u30b9\u306e\u8868\u793a\u8a2d\u5b9a\u3092\u884c\u3044\u307e\u3059\u3002<\/td><\/tr><tr><td><br>main.js<\/td><td>\u30e1\u30a4\u30f3\u30b9\u30af\u30ea\u30d7\u30c8<\/td><td><strong>\u65b0\u898f\u4f5c\u6210<\/strong><br>Three.js\u306e\u30b3\u30fc\u30c9\u3092\u8a18\u8ff0\u3057\u30013D\u30b7\u30fc\u30f3\u306e\u69cb\u7bc9\u3068\u63cf\u753b\u3092\u5b9f\u884c\u3057\u307e\u3059\u3002<\/td><\/tr><tr><td>three.module.js<\/td><td>\u30e9\u30a4\u30d6\u30e9\u30ea<\/td><td>Three.js \u306e ES Module\u7248\uff08import\/export\u65b9\u5f0f\uff09<br><strong>\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u5148<\/strong><br><a href=\"https:\/\/unpkg.com\/three@0.165.0\/build\/three.module.js\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/unpkg.com\/three@0.165.0\/build\/three.module.js<\/a><\/td><\/tr><tr><td>OrbitControls.js<\/td><td>\u30e9\u30a4\u30d6\u30e9\u30ea<\/td><td>Three.js\u3067\u30ab\u30e1\u30e9\u3092\u30de\u30a6\u30b9\u3084\u30bf\u30c3\u30c1\u3067\u64cd\u4f5c\u3067\u304d\u308b\u3088\u3046\u306b\u3059\u308b\u305f\u3081\u306e\u62e1\u5f35\u30e9\u30a4\u30d6\u30e9\u30ea\u3002<br>Three.js\u306e\u672c\u4f53\u306b\u306f\u542b\u307e\u308c\u3066\u304a\u3089\u305a\u3001examples\/jsm\/controls\/ \u306b\u3042\u308b\u8ffd\u52a0\u30e2\u30b8\u30e5\u30fc\u30eb\u3067\u3059\u3002<br><strong>\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u5148<\/strong><br><a href=\"https:\/\/unpkg.com\/three@0.165.0\/examples\/jsm\/controls\/OrbitControls.js\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/unpkg.com\/three@0.165.0\/examples\/jsm\/controls\/OrbitControls.js<\/a><\/td><\/tr><tr><td>GLTFLoader.js<\/td><td>\u30e9\u30a4\u30d6\u30e9\u30ea<\/td><td>Three.js\u3067Blender\u3084ZBrush\u306a\u3069\u3067\u4f5c\u6210\u3057\u305f\u300c\u30b9\u30ab\u30eb\u30d7\u30c8\uff08\u5f6b\u523b\uff09\u300d\u306b\u3088\u3063\u3066\u8907\u96d1\u306b\u5909\u5f62\u3057\u305f3D\u30e2\u30c7\u30eb\u3092\u5229\u7528\u3059\u308b\u3002<br>Three.js\u306e\u672c\u4f53\u306b\u306f\u542b\u307e\u308c\u3066\u304a\u3089\u305a\u3001examples\/jsm\/loaders\/ \u306b\u3042\u308b\u8ffd\u52a0\u30e2\u30b8\u30e5\u30fc\u30eb\u3067\u3059\u3002<br><strong>\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u5148<\/strong><br><a href=\"https:\/\/unpkg.com\/three@0.165.0\/examples\/jsm\/loaders\/GLTFLoader.js\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/unpkg.com\/three@0.165.0\/examples\/jsm\/loaders\/GLTFLoader.js<\/a><\/td><\/tr><tr><td>BufferGeometryUtils.js<\/td><td>\u30e9\u30a4\u30d6\u30e9\u30ea<\/td><td>BufferGeometry \u306e\u64cd\u4f5c\u3092\u4fbf\u5229\u306b\u3059\u308b\u30e6\u30fc\u30c6\u30a3\u30ea\u30c6\u30a3\u96c6\u3002GLTFLoader.js\u3067\u4f7f\u7528\u3055\u308c\u307e\u3059\u3002<br>Three.js \u306e\u672c\u4f53\u306b\u306f\u542b\u307e\u308c\u3066\u304a\u3089\u305a\u3001examples\/jsm\/utils\/ \u306b\u3042\u308b\u8ffd\u52a0\u30e2\u30b8\u30e5\u30fc\u30eb\u3067\u3059\u3002<br><strong>\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u5148<\/strong><br><a href=\"https:\/\/unpkg.com\/three@0.165.0\/examples\/jsm\/utils\/BufferGeometryUtils.js\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/unpkg.com\/three@0.165.0\/examples\/jsm\/utils\/BufferGeometryUtils.js<\/a><\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\">\u958b\u767a\u306b\u5fc5\u8981\u306a\u30d5\u30a1\u30a4\u30eb\u69cb\u6210<\/figcaption><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u30d5\u30a9\u30eb\u30c0\u3092\u4f5c\u6210\u3057\u3066\u5fc5\u8981\u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u8a2d\u7f6e\u3059\u308b<\/h3>\n\n\n\n<p>Windows\u306e\u4f8b\u3068\u3057\u3066\u3001\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u30d5\u30a9\u30eb\u30c0\u3092\u4f5c\u6210\u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n\n\n\n<div class=\"wp-block-luxe-blocks-border-block\" style=\"margin-top:10px;margin-bottom:30px\"><div class=\"wp-block-luxe-blocks-border-block-content\" style=\"border:1px solid #006edc;border-radius:0px;padding:0px 15px 0px 15px\">\n<p><strong>c:\\projects\\3d<\/strong><br>c:\\projects\\3d\\jsm\\controls<br>c:\\projects\\3d\\jsm\\loaders<br>c:\\projects\\3d\\jsm\\utils<\/p>\n<\/div><\/div>\n\n\n\n<p>\u30d5\u30a9\u30eb\u30c0\u306f\u9069\u5b9c\u81ea\u8eab\u306e\u74b0\u5883\u3067\u90fd\u5408\u306e\u826f\u3044\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3067\u304b\u307e\u3044\u307e\u305b\u3093\u3002.\\jsm\u30d5\u30a9\u30eb\u30c0\u306f\u4f8b\u306e\u3088\u3046\u306b\u3057\u3066\u304f\u3060\u3055\u3044\u3002three\u306e\u30e9\u30a4\u30d6\u30e9\u30ea\u304c.\\jsm\u914d\u4e0b\u3092\u53c2\u7167\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u958b\u767a\u306b\u5fc5\u8981\u306a\u30d5\u30a1\u30a4\u30eb\u69cb\u6210\u3067\uff14\u3064\u306e\u30d5\u30a1\u30a4\u30ebthree.module.js\u3001OrbitControls.js\u3001GLTFLoader.js\u3001BufferGeometryUtils.js\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3057\u307e\u3059\u3002<br>\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u5148\u306f\u8868\u5185\u306eURL\u30ea\u30f3\u30af\u3092\u53c2\u7167\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u30a2\u30af\u30bb\u30b9\u3059\u308b\u3068js\u30d5\u30a1\u30a4\u30eb\u306e\u5185\u5bb9\u304c\u30d6\u30e9\u30a6\u30b6\u306b\u8868\u793a\u3055\u308c\u307e\u3059\u306e\u3067\u3001\u30d6\u30e9\u30a6\u30b6\u4e0a\u3067\u53f3\u30af\u30ea\u30c3\u30af\u3057\u3001\u540d\u524d\u3092\u4ed8\u3051\u3066\u6240\u5b9a\u306e\u30d5\u30a9\u30eb\u30c0\u306b\u4fdd\u5b58\u3057\u3066\u304f\u3060\u3055\u3044\u3002<br><img decoding=\"async\" class=\"wp-image-49174\" style=\"width: 420px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-9.png\" alt=\"\u30d5\u30a9\u30eb\u30c0\u30fb\u30d5\u30a1\u30a4\u30eb\u69cb\u6210\"><br>VS Code\u3092\u8d77\u52d5\u3055\u305b\u3001\u300c\u30d5\u30a1\u30a4\u30eb\u300d-\u300c\u30d5\u30a9\u30eb\u30c0\u3092\u958b\u304f\u300d\u3092\u5b9f\u884c\u3057\u3066\u4f5c\u6210\u3057\u305f\u30d5\u30a9\u30eb\u30c0<strong>c:\\projects\\3d<\/strong>\u3092\u9078\u629e\u3057\u3066\u958b\u3044\u3066\u304f\u3060\u3055\u3044\u3002<br><img decoding=\"async\" class=\"wp-image-49177\" style=\"width: 640px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-1.png\" alt=\"VS Code\u30d5\u30a9\u30eb\u30c0\u30fc\u30aa\u30fc\u30d7\u30f3\u753b\u9762\"><\/p>\n\n\n\n<p>\u6240\u5b9a\u306e\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306b\u6b63\u3057\u304f\u30d5\u30a1\u30a4\u30eb\u304c\u914d\u7f6e\u3055\u308c\u3066\u3044\u308b\u3053\u3068\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002<br>\u3053\u3053\u304b\u3089VS Code\u4e0a\u3067\u3001index.html\u3001style.css\u3001main.js\u3092\u4f5c\u6210\u3057\u3001\u3053\u306emain.js\u306b\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u5f62\u3067\u9032\u3081\u3066\u3044\u304d\u307e\u3059\u3002\uff08\u30d5\u30a1\u30a4\u30eb\u306e\u65b0\u898f\u4f5c\u6210\u3001\u66f4\u65b0\u3001\u4fdd\u5b58\u65b9\u6cd5\u306f\u4ed6\u306e\u30a8\u30c7\u30a3\u30bf\u30fc\u30c4\u30fc\u30eb\u3092\u540c\u3058\u3088\u3046\u306b\u5de6\u4e0a\u306e\u300c\u30d5\u30a1\u30a4\u30eb\u300d\u304b\u3089\u64cd\u4f5c\u3067\u304d\u307e\u3059\u3002\uff09<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">index.html\u3001style.css\u3001main.js\u30d5\u30a1\u30a4\u30eb\u306e\u4f5c\u6210<\/h2>\n\n\n\n<p>\u6a5f\u80fd\u306e\u8ffd\u52a0\u306f\u4ee5\u4e0b\u306e\u9806\u306b\u5f93\u3063\u3066\u62e1\u5f35\u3057\u3066\u3044\u304d\u307e\u3059\u3002<br>\u5404\u6bb5\u968e\u306e\u52d5\u4f5c\u306fVS Code\u306e\u62e1\u5f35\u6a5f\u80fdLive Server\u3067\u78ba\u8a8d\u3067\u304d\u307e\u3059\u3002\u78ba\u8a8d\u65b9\u6cd5\u306f\u5f8c\u307b\u3069\u8a18\u8f09\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<div class=\"wp-block-luxe-blocks-topic\" style=\"margin-top:10px;margin-bottom:30px\"><div class=\"wp-block-luxe-blocks-topic-title\" style=\"color:#fff;background-color:#006edc;border:1px solid #006edc;padding:2px 14px;align-items:center\">\u4e3b\u306a\u6a5f\u80fd\u4e00\u89a7<\/div><div class=\"wp-block-luxe-blocks-topic-content\" style=\"border:1px solid #006edc;padding:0px 15px 0px 15px\">\n\n<ol type=\"1\">\n\n<li>3D\u30b7\u30fc\u30f3\u306e\u4f5c\u6210<\/li>\n\n\n<li>\u90e8\u5c4b\uff08\u5e8a\u3068\u58c1\uff09\u306e\u4f5c\u6210<\/li>\n\n\n<li>\u7c21\u5358\u306a\u76f4\u65b9\u4f53\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u8a2d\u7f6e\uff08\u673a\u3001\u6905\u5b50\u304a\u3088\u3073\u68da\uff09<\/li>\n\n\n<li>\u8907\u6570\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u30b0\u30eb\u30fc\u30d7\u5316\u3057\u305f\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u8a2d\u7f6e\uff08\u6905\u5b50\uff09<\/li>\n\n\n<li>3D\u30e2\u30c7\u30eb\u306e\u8a2d\u7f6e\uff08\u9f8d\u306e\u7f6e\u7269\uff09<\/li>\n\n\n<li>\u30c9\u30e9\u30c3\u30b0\uff06\u30c9\u30ed\u30c3\u30d7\u306b\u3088\u308b\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u79fb\u52d5<\/li>\n\n\n<li>\u56de\u8ee2\u30ac\u30a4\u30c9\u30ea\u30f3\u30b0\u64cd\u4f5c\u3067\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u56de\u8ee2<\/li>\n\n\n<li>\u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u306e\u8a2d\u7f6e\uff08\u5f71\u306e\u751f\u6210\uff09\u3068\u79fb\u52d5\u3001\u8a2d\u5b9a\u4f4d\u7f6e\u306e\u4fdd\u5b58\u3068\u5143\u306b\u623b\u3059\u6a5f\u80fd\u306e\u8ffd\u52a0<\/li>\n\n<\/ol>\n\n<\/div><\/div>\n\n\n\n<p>\u203b\u5fc5\u8981\u306a\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u306f\u672c\u8a18\u4e8b\u4e2d\u3067\u30b9\u30c6\u30c3\u30d7\u3054\u3068\u306b\u8a18\u8f09\u3057\u3066\u3044\u307e\u3059\u306e\u3067\u3001\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u3092\u30b3\u30d4\u30fc\u3057\u306a\u304c\u3089\u8ffd\u52a0\u6a5f\u80fd\u3092\u5b9f\u88c5\u3057\u3001\u52d5\u4f5c\u78ba\u8a8d\u304c\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u3066\u3044\u307e\u3059\u3002<br>\u307e\u305f\u3001<a href=\"https:\/\/github.com\/picolix\/Three.js-Room-Layout-Editor\/archive\/refs\/heads\/main.zip\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/picolix\/Three.js-Room-Layout-Editor\/archive\/refs\/heads\/main.zip<\/a>\u306b\u3082\u30b9\u30c6\u30c3\u30d7\u6bce\u306e\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u3001\u5b8c\u6210\u7248\u306e\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u3092\u30a2\u30c3\u30d7\u3057\u3066\u3044\u307e\u3059\u306e\u3067\u53c2\u8003\u306b\u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">&nbsp;HTML\u30d5\u30a1\u30a4\u30eb\u306e\u4f5c\u6210 (index.html)<\/h3>\n\n\n\n<p>Three.js\u30e9\u30a4\u30d6\u30e9\u30ea\u306e\u8aad\u307f\u8fbc\u307f\u3068\u3001JavaScript\u30d5\u30a1\u30a4\u30eb\u306e\u8aad\u307f\u8fbc\u307f\u3092\u884c\u3046\u57fa\u672c\u7684\u306aHTML\u69cb\u9020\u3092\u8a18\u8ff0\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<p><strong>index.html<\/strong><br>VS Code\u3067\u300c\u30d5\u30a1\u30a4\u30eb\u300d-\u300c\u65b0\u3057\u3044\u30d5\u30a1\u30a4\u30eb\u300d\u3092\u5b9f\u884c\u3057\u3066\u30d5\u30a1\u30a4\u30eb\u540d\u3092index.html\u3068\u3057\u3066\u30aa\u30fc\u30d7\u30f3\u3057\u3066\u304f\u3060\u3055\u3044\u3002<br>\u4ee5\u4e0b\u306e\u30b3\u30fc\u30c9\u3092\u30b3\u30d4\u30fc\u3057\u3066\u4fdd\u5b58\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u3053\u306eindex.html\u306f\u4eca\u5f8c\u306e\u6a5f\u80fd\u8ffd\u52a0\u3067\u3082\u4e00\u5207\u5909\u66f4\u306f\u3042\u308a\u307e\u305b\u3093\u3002<\/p>\n\n\n<pre class=\"line-numbers\"><code class=\"language-markup\">&lt;!DOCTYPE html&gt;\n&lt;html lang=\"ja\"&gt;\n&lt;head&gt;\n    &lt;meta charset=\"UTF-8\"&gt;\n    &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"&gt;\n    &lt;title&gt;3D\u30ec\u30a4\u30a2\u30a6\u30c8\u30b7\u30df\u30e5\u30ec\u30fc\u30bf\u30fc&lt;\/title&gt;\n    &lt;link rel=\"stylesheet\" href=\"style.css\"&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;div id=\"controls\"&gt;\n        &lt;button id=\"saveButton\"&gt;\u4fdd\u5b58&lt;\/button&gt;\n        &lt;button id=\"loadButton\"&gt;\u623b\u3059&lt;\/button&gt;\n    &lt;\/div&gt;\n    &lt;div id=\"customDialog\" class=\"hidden\"&gt;\n        &lt;p id=\"dialogMessage\"&gt;&lt;\/p&gt;\n    &lt;\/div&gt;\n    &lt;script type=\"importmap\"&gt;{\n        \"imports\": {\n          \"three\": \".\/three.module.js\"\n        }\n      }\n    &lt;\/script&gt;\n    &lt;script src=\"main.js\" type=\"module\"&gt;&lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n\n\n<p><img decoding=\"async\" class=\"wp-image-49196\" style=\"width: 640px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-3.png\" alt=\"VS Code \u65b0\u898f\u30d5\u30a1\u30a4\u30eb\u4f5c\u6210\"><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">CSS\u30d5\u30a1\u30a4\u30eb\u306e\u4f5c\u6210(style.css)<\/h3>\n\n\n\n<p>3D\u63cf\u753b\u30a8\u30ea\u30a2\uff08<code>canvas<\/code>\u8981\u7d20\uff09\u304c\u30a6\u30a3\u30f3\u30c9\u30a6\u5168\u4f53\u306b\u5e83\u304c\u308b\u3088\u3046\u306b\u3001\u57fa\u672c\u7684\u306a\u30ea\u30bb\u30c3\u30c8\u3068\u30b9\u30bf\u30a4\u30eb\u3092\u8a2d\u5b9a\u3057\u307e\u3059\u3002\u3053\u308c\u306b\u3088\u308a\u3001\u5168\u753b\u9762\u30673D\u30b3\u30f3\u30c6\u30f3\u30c4\u3092\u8868\u793a\u3067\u304d\u307e\u3059\u3002<br>\u3053\u306estyle.css\u3082\u4eca\u5f8c\u306e\u6a5f\u80fd\u8ffd\u52a0\u3067\u3082\u4e00\u5207\u5909\u66f4\u306f\u3042\u308a\u307e\u305b\u3093\u3002<\/p>\n\n\n\n<p><strong>style.css<\/strong><\/p>\n\n\n<pre class=\"line-numbers\"><code class=\"language-css\">\/* style.css *\/\nbody {\n    margin: 0;\n    overflow: hidden; \/* \u30b9\u30af\u30ed\u30fc\u30eb\u30d0\u30fc\u3092\u975e\u8868\u793a *\/\n}\n\/* Three.js\u304c\u751f\u6210\u3059\u308b\u30ad\u30e3\u30f3\u30d0\u30b9\u8981\u7d20\u306b\u5bfe\u3059\u308b\u30b9\u30bf\u30a4\u30eb\u8a2d\u5b9a *\/\ncanvas {\n    display: block; \/* \u30a4\u30f3\u30e9\u30a4\u30f3\u8981\u7d20\u306b\u3088\u308b\u9699\u9593\u3092\u9632\u3050 *\/\n}\n\/* \u4fdd\u5b58\u30fb\u623b\u3059\u30dc\u30bf\u30f3\u306e\u30b9\u30bf\u30a4\u30eb *\/\n#controls {\n    position: absolute;\n    top: 10px;\n    right: 10px;\n    z-index: 101; \/* 3D\u30ad\u30e3\u30f3\u30d0\u30b9\u306e\u4e0a\u306b\u8868\u793a *\/\n    display: flex;\n    gap: 10px;\n}\n#controls button {\n    padding: 10px 15px;\n    font-size: 16px;\n    cursor: pointer;\n    background-color: #4CAF50;\n    color: white;\n    border: none;\n    border-radius: 5px;\n    box-shadow: 0 2px 5px rgba(0,0,0,0.2);\n    transition: background-color 0.2s;\n}\n#controls button:hover {\n    background-color: #45a049;\n}\n\n\/* \u30ab\u30b9\u30bf\u30e0\u30c0\u30a4\u30a2\u30ed\u30b0\u306e\u30b9\u30bf\u30a4\u30eb *\/\n#customDialog {\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    transform: translate(-50%, -50%);\n    background-color: rgba(0, 0, 0, 0.8); \/* \u901a\u5e38\uff08\u6210\u529f\u6642\uff09\u306e\u80cc\u666f\u8272 *\/\n    color: white;\n    padding: 15px 30px;\n    border-radius: 8px;\n    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4);\n    z-index: 1000;\n    opacity: 1;\n    transition: opacity 0.5s, visibility 0.5s;\n    text-align: center;\n}\n#customDialog.hidden {\n    opacity: 0;\n    visibility: hidden; \/* \u975e\u8868\u793a\u6642\u306b\u30af\u30ea\u30c3\u30af\u3067\u304d\u306a\u3044\u3088\u3046\u306b\u3059\u308b *\/\n}\n#customDialog p {\n    margin: 0;\n    font-weight: bold;\n}\n\/* \u30a8\u30e9\u30fc\u6642\u306e\u30b9\u30bf\u30a4\u30eb *\/\n#customDialog.error {\n    background-color: #d32f2f; \/* \u30a8\u30e9\u30fc\uff08\u8d64\u7cfb\uff09\u306e\u80cc\u666f\u8272 *\/\n}\n<\/code><\/pre>\n\n\n<p><img decoding=\"async\" class=\"wp-image-49202\" style=\"width: 640px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-4.png\" alt=\"VS Code \u65b0\u898fstyle.css\u30d5\u30a1\u30a4\u30eb\u4f5c\u6210\"><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u30e1\u30a4\u30f3\u30d7\u30ed\u30b0\u30e9\u30e0\u30d5\u30a1\u30a4\u30eb\u306e\u4f5c\u6210 (main.js)<\/h3>\n\n\n\n<p><code>main.js<\/code>\u30d5\u30a1\u30a4\u30eb\u306b\u3001Three.js\u3092\u4f7f\u3063\u305f\u57fa\u672c\u7684\u306a3D\u30b7\u30fc\u30f3\uff08\u4e16\u754c\uff09\u3092\u69cb\u7bc9\u3059\u308b\u305f\u3081\u306e\u521d\u671f\u8a2d\u5b9a\u30b3\u30fc\u30c9\u3092\u8a18\u8ff0\u3057\u307e\u3059\u3002<br>3D\u30b7\u30fc\u30f3\u3092\u69cb\u7bc9\u3059\u308b\u305f\u3081\u306b\u3001\u307e\u305a\u4ee5\u4e0b\u306e3\u3064\u306e\u6838\u3068\u306a\u308b\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u5b9a\u7fa9\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<ol type=\"1\" class=\"has-whitesmoke-background-color has-background\">\n<li>Scene\uff08\u30b7\u30fc\u30f3\uff09\uff1a3D\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3001\u30e9\u30a4\u30c8\u3001\u30ab\u30e1\u30e9\u306a\u3069\u3001\u3059\u3079\u3066\u3092\u914d\u7f6e\u3059\u308b\u4eee\u60f3\u4e16\u754c\u306e\u5165\u308c\u7269\u3002<\/li>\n\n\n\n<li>Camera\uff08\u30ab\u30e1\u30e9\uff09\uff1a\u30b7\u30fc\u30f3\u306e\u4e2d\u306e\u8996\u70b9\u3002\u30e6\u30fc\u30b6\u30fc\u304c\u3069\u3053\u304b\u3089\u4e16\u754c\u3092\u898b\u3066\u3044\u308b\u304b\u3092\u6c7a\u5b9a\u3057\u307e\u3059\u3002<\/li>\n\n\n\n<li>Renderer\uff08\u30ec\u30f3\u30c0\u30e9\u30fc\uff09\uff1a\u30b7\u30fc\u30f3\u3068\u30ab\u30e1\u30e9\u304c\u8a2d\u5b9a\u3055\u308c\u305f\u753b\u50cf\u3092\u751f\u6210\u3057\u3001HTML\u306e <code>&lt;canvas&gt;<\/code> \u8981\u7d20\u306b\u63cf\u753b\u3059\u308b\u5f79\u5272\u3092\u62c5\u3044\u307e\u3059\u3002<\/li>\n<\/ol>\n\n\n\n<p>\u57fa\u672c\u3068\u306a\u308b\u30d7\u30ed\u30b0\u30e9\u30e0main.js\u306f\u4ee5\u4e0b\u3067\u3059\u3002\u6a5f\u80fd\u8ffd\u52a0\u306f\u3053\u306emain.js\u3092\u57fa\u306b\u6539\u9020\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<p><strong>main.js<\/strong><\/p>\n\n\n<pre class=\"line-numbers\" data-line=\"3\"><code class=\"language-javascript\">\/\/ main.js\n\/\/ [main-000-base]\n\/\/ index.html \u306e importmap \u306e\u8a2d\u5b9a\u306b\u57fa\u3065\u304d\u3001\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\u3092\u30a4\u30f3\u30dd\u30fc\u30c8\nimport * as THREE from \"three\";\nimport { OrbitControls } from '.\/jsm\/controls\/OrbitControls.js';\n\n\/\/ \u5fc5\u8981\u306a\u5909\u6570\u3092\u30b0\u30ed\u30fc\u30d0\u30eb\u30b9\u30b3\u30fc\u30d7\u3067\u5b9a\u7fa9\nlet scene, camera, renderer, controls;\n\n\/\/ 1. \u521d\u671f\u5316\u95a2\u6570\uff1a3D\u4e16\u754c\u306e\u571f\u53f0\u3092\u4f5c\u308b\nfunction init() {\n    \/\/ === 1-1. \u30b7\u30fc\u30f3 (Scene) \u306e\u4f5c\u6210 ===\n    scene = new THREE.Scene();\n    scene.background = new THREE.Color(0xf0f0f0); \/\/ \u80cc\u666f\u8272\u3092\u8584\u3044\u30b0\u30ec\u30fc\u306b\u8a2d\u5b9a\n    \n    \/\/ \u5ea7\u6a19\u8ef8\u30d8\u30eb\u30d1\u30fc\u3092\u8ffd\u52a0\uff08X\u8ef8\uff1a\u8d64\u3001Y\u8ef8\uff1a\u7dd1\u3001Z\u8ef8\uff1a\u9752\uff09\n    const axesHelper = new THREE.AxesHelper(10); \/\/ \u30b5\u30a4\u30ba10\n    scene.add(axesHelper);\n\n    \/\/ === 1-2. \u30ab\u30e1\u30e9 (Camera) \u306e\u8a2d\u5b9a ===\n    const fov = 75; \/\/ \u8996\u91ce\u89d2 (Field of View)\n    const aspect = window.innerWidth \/ window.innerHeight; \/\/ \u30a2\u30b9\u30da\u30af\u30c8\u6bd4\n    const near = 0.1; \/\/ \u63cf\u753b\u958b\u59cb\u8ddd\u96e2\n    const far = 1000; \/\/ \u63cf\u753b\u7d42\u4e86\u8ddd\u96e2\n    camera = new THREE.PerspectiveCamera(fov, aspect, near, far);\n    \n    \/\/ \u30ab\u30e1\u30e9\u306e\u521d\u671f\u4f4d\u7f6e\u3092\u6c7a\u5b9a (X, Y, Z)\n    camera.position.set(10, 15, 15);\n    camera.lookAt(0, 0, 0); \/\/ \u539f\u70b9(0, 0, 0)\u3092\u898b\u308b\u3088\u3046\u306b\u8a2d\u5b9a\n\n    \/\/ === 1-3. \u30ec\u30f3\u30c0\u30e9\u30fc (Renderer) \u306e\u4f5c\u6210 ===\n    renderer = new THREE.WebGLRenderer({ antialias: true }); \/\/ \u30a2\u30f3\u30c1\u30a8\u30a4\u30ea\u30a2\u30b9\u3067\u63cf\u753b\u3092\u6ed1\u3089\u304b\u306b\n    renderer.setSize(window.innerWidth, window.innerHeight); \/\/ \u63cf\u753b\u30b5\u30a4\u30ba\u3092\u30a6\u30a3\u30f3\u30c9\u30a6\u30b5\u30a4\u30ba\u306b\u5408\u308f\u305b\u308b\n    \n    \/\/ \u751f\u6210\u3055\u308c\u305f&lt;canvas&gt;\u8981\u7d20\u3092HTML&lt;body&gt;\u306b\u8ffd\u52a0\n    document.body.appendChild(renderer.domElement);\n\n    \/\/ === 1-4. \u30ab\u30e1\u30e9\u64cd\u4f5c (OrbitControls) \u306e\u8a2d\u5b9a ===\n    \/\/ \u30a4\u30f3\u30dd\u30fc\u30c8\u3057\u305f OrbitControls \u3092\u4f7f\u3063\u3066\u3001\u30de\u30a6\u30b9\u3067\u30ab\u30e1\u30e9\u3092\u52d5\u304b\u305b\u308b\u3088\u3046\u306b\u3059\u308b\n    controls = new OrbitControls(camera, renderer.domElement);\n    controls.enableDamping = true; \/\/ \u52d5\u304d\u3092\u6ed1\u3089\u304b\u306b\u3059\u308b\n    controls.dampingFactor = 0.05;\n\n    \/\/ \u30a6\u30a3\u30f3\u30c9\u30a6\u30b5\u30a4\u30ba\u304c\u5909\u66f4\u3055\u308c\u305f\u3068\u304d\u306e\u30ea\u30b5\u30a4\u30ba\u51e6\u7406\u3092\u767b\u9332\n    window.addEventListener('resize', onWindowResize, false);\n}\n\n\/\/ 2. \u63cf\u753b\u30eb\u30fc\u30d7\u95a2\u6570\uff1a\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u306e\u5fc3\u81d3\u90e8\nfunction animate() {\n    requestAnimationFrame(animate); \/\/ \u30d6\u30e9\u30a6\u30b6\u306e\u518d\u63cf\u753b\u30bf\u30a4\u30df\u30f3\u30b0\u306b\u5408\u308f\u305b\u3066\u30eb\u30fc\u30d7\u3092\u7d99\u7d9a\n    controls.update(); \/\/ \u30ab\u30e1\u30e9\u64cd\u4f5c\u306e\u30c0\u30f3\u30d4\u30f3\u30b0\u52b9\u679c\u3092\u9069\u7528\u3059\u308b\u305f\u3081\u306b\u66f4\u65b0\u304c\u5fc5\u8981\n    renderer.render(scene, camera); \/\/ \u30b7\u30fc\u30f3\u3092\u30ab\u30e1\u30e9\u306e\u8996\u70b9\u304b\u3089\u63cf\u753b\n}\n\n\/\/ 3. \u30a6\u30a3\u30f3\u30c9\u30a6\u30ea\u30b5\u30a4\u30ba\u51e6\u7406\uff1a\u753b\u9762\u30b5\u30a4\u30ba\u304c\u5909\u308f\u3063\u3066\u3082\u8868\u793a\u3092\u6700\u9069\u5316\nfunction onWindowResize() {\n    camera.aspect = window.innerWidth \/ window.innerHeight;    \/\/ \u30ab\u30e1\u30e9\u306e\u30a2\u30b9\u30da\u30af\u30c8\u6bd4\u66f4\u65b0\n    camera.updateProjectionMatrix(); \/\/ \u30ab\u30e1\u30e9\u306e\u6295\u5f71\u884c\u5217\u3092\u66f4\u65b0\n    renderer.setSize(window.innerWidth, window.innerHeight); \/\/ \u30ec\u30f3\u30c0\u30e9\u30fc\u306e\u30b5\u30a4\u30ba\u66f4\u65b0\n}\n\n\/\/ \u5b9f\u884c\ninit();\nanimate();\n\n<\/code><\/pre>\n\n\n<p><img decoding=\"async\" class=\"wp-image-49204\" style=\"width: 640px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-5.png\" alt=\"VS Code \u65b0\u898fmain.js\u30d5\u30a1\u30a4\u30eb\u4f5c\u6210\"><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u5b9f\u884c\u7d50\u679c\u306e\u78ba\u8a8d<\/h3>\n\n\n\n<p>index.html\u30d5\u30a1\u30a4\u30eb\u3092\u53f3\u30af\u30ea\u30c3\u30af\u3057\u300c\u30d7\u30ec\u30d3\u30e5\u30fc\u306e\u8868\u793a\u300d\u3092\u30af\u30ea\u30c3\u30af\u3057\u3066\u304f\u3060\u3055\u3044\u3002<br><img decoding=\"async\" class=\"wp-image-49207\" style=\"width: 640px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-6.png\" alt=\"VS Code\u30d7\u30ec\u30d3\u30e5\u30fc\u8868\u793a\u306e\u5b9f\u884c\"><br><br>\u30d3\u30e5\u30ef\u30fc\u9818\u57df\u4e0a\u3067\u80cc\u666f\u304c\u8584\u3044\u30b0\u30ec\u30fc\u306b\u306a\u308a\u3001\u539f\u70b9\u3092\u793a\u3059\uff13\u8272\u306e\u5ea7\u6a19\u8ef8\u304c\u8868\u793a\u3055\u308c\u3066\u3044\u308c\u3070\u6210\u529f\u3067\u3059\u3002<\/p>\n\n\n\n<ul>\n<li><strong>\u8d64\u7dda\uff1aX\u8ef8 (\u5de6\u53f3)<\/strong><\/li>\n\n\n\n<li><strong>\u7dd1\u7dda\uff1aY\u8ef8 (\u4e0a\u4e0b)<\/strong><\/li>\n\n\n\n<li><strong>\u9752\u7dda\uff1aZ\u8ef8 (\u5965\u884c\u304d)<\/strong><\/li>\n<\/ul>\n\n\n\n<p><img decoding=\"async\" class=\"wp-image-49208\" style=\"width: 640px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-7.png\" alt=\"VS Code\u5b9f\u884c\u7d50\u679c\u306e\u78ba\u8a8d\"><br>\u203b\u753b\u9762\u4e0b\u30b9\u30c6\u30fc\u30bf\u30b9\u6b04\u306e\u300cGo LIVE\u300d\u3092\u30af\u30ea\u30c3\u30af\u3059\u308b\u3068\u30d6\u30e9\u30a6\u30b6\u304c\u7acb\u3061\u4e0a\u304c\u3063\u3066\u540c\u3058\u753b\u9762\u304c\u8868\u793a\u3055\u308c\u307e\u3059\u3002\u958b\u767a\u3057\u3084\u3059\u3044\u74b0\u5883\u3067\u5229\u7528\u3057\u3066\u304f\u3060\u3055\u3044\u3002<br>\u7b46\u8005\u306f\u4e21\u65b9\u4f7f\u7528\u3057\u3066\u3044\u307e\u3059\u3002\u30d6\u30e9\u30a6\u30b6\u5229\u7528\u3067\u306f\u306a\u3093\u3089\u304b\u306e\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u753b\u9762\u304c\u771f\u3063\u767d\u306b\u306a\u3063\u305f\u6642\u306b\u30d6\u30e9\u30a6\u30b6\u306e\u958b\u767a\u30c4\u30fc\u30eb\u3092\u8d77\u52d5\u3055\u305b\u3066\u30a8\u30e9\u30fc\u7b87\u6240\u3068\u5185\u5bb9\u3092\u78ba\u8a8d\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<p><strong>\u30de\u30a6\u30b9\u306e\u5de6\u30af\u30ea\u30c3\u30af\u3067\u56de\u8ee2\u3001\u53f3\u30af\u30ea\u30c3\u30af\u3067\u79fb\u52d5\u3001\u30db\u30a4\u30fc\u30eb\u3067\u30ba\u30fc\u30e0\u304c\u3067\u304d\u308b\u3088\u3046\u306b\u306a\u3063\u3066\u3044\u308b\u306f\u305a\u3067\u3059\u3002<\/strong><\/p>\n\n\n\n<div class=\"wp-block-group has-lightyellow-background-color has-background is-layout-constrained wp-block-group-is-layout-constrained\" style=\"padding-top:10px;padding-right:20px;padding-bottom:10px;padding-left:20px\"><div class=\"wp-block-group__inner-container\">\n<p><img decoding=\"async\" class=\"wp-image-43032\" style=\"width: 32px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/09\/ddns-19.png\" alt=\"\u30ef\u30f3\u30dd\u30a4\u30f3\u30c8\u30d2\u30f3\u30c8\"><strong>\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\u30fc\u30b0\u30e9\u30d5\u30a3\u30c3\u30af\u30b9\uff08CG\uff09\u30843D\u30e2\u30c7\u30ea\u30f3\u30b0<\/strong>\u306b\u304a\u3051\u308b\u5ea7\u6a19\u7cfb\u306e\u6163\u7fd2<\/p>\n\n\n\n<p>\u6570\u5b66\u3067\u4e00\u822c\u7684\u306b\u4f7f\u308f\u308c\u308b\u30c7\u30ab\u30eb\u30c8\u5ea7\u6a19\u7cfb\u3067\u306fX,Y\u8ef8\u304c\u5e73\u9762\u3001Z\u8ef8\u304c\u9ad8\u3055\u3067\u8868\u73fe\u3055\u308c\u307e\u3059\u3002\u76f4\u611f\u7684\u306b\u3082\u3053\u308c\u304c\u81ea\u7136\u3067\u3059\u304c\u30013D\u30c4\u30fc\u30eb\u3067\u306f\u6163\u7fd2\u7684\u306a\u5ea7\u6a19\u7cfb\u3067\u3042\u308bY-up\u65b9\u5f0f\u304c\u63a1\u7528\u3055\u308c\u307e\u3059\u3002<br>\u591a\u304f\u306e\u4e3b\u8981\u306a3D\u30c4\u30fc\u30eb\uff08\u4f8b\uff1aBlender, Maya, Unity, Unreal Engine\uff09\u3067\u306f\u3001\u3053\u306e\u6163\u7fd2\u304c\u63a1\u7528\u3055\u308c\u3066\u3044\u307e\u3059\u3002\u3053\u308c\u3092Y-up\u307e\u305f\u306f<strong>Y-\u8ef8\u304c\u5782\u76f4\uff08\u30a2\u30c3\u30d1\u30fc\uff09<\/strong>\u65b9\u5f0f\u3068\u547c\u3073\u307e\u3059\u3002<\/p>\n<\/div><\/div>\n\n\n\n<p><strong>3D\u7a7a\u9593\u3067XYZ\u8ef8\u3092\u8868\u793a\u3059\u308b\u3053\u3068\u306f\u30013D\u958b\u767a\u306b\u304a\u3051\u308b\u300e\u306f\u3058\u3081\u3066\u306e\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0\u300f\u306e\u3088\u3046\u306a\u3082\u306e\u3067\u3059\u3002\u3053\u308c\u304c\u3067\u304d\u308b\u3088\u3046\u306b\u306a\u308c\u3070\u3001\u3042\u306a\u305f\u3082\u7acb\u6d3e\u306a3D\u958b\u767a\u306e\u4ef2\u9593\u5165\u308a\u3067\u3059\u3002<\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3D\u4e16\u754c\u306b\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u8a2d\u7f6e<\/h2>\n\n\n\n<p>\u3053\u308c\u30673D\u4e16\u754c\u306e\u571f\u53f0\u306b\u90e8\u5c4b\u306e\u69cb\u9020\u3084\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u4f5c\u3063\u3066\u3044\u304d\u307e\u3059\u3002\u5143\u306emain.js\u306b\u6a5f\u80fd\u3092\u8ffd\u52a0\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u90e8\u5c4b\uff08\u5e8a\u3068\u58c1\uff09\u306e\u4f5c\u6210<\/h3>\n\n\n\n<p><code>main.js<\/code>\u30d5\u30a1\u30a4\u30eb\u306b\u3001Three.js\u3092\u4f7f\u3063\u305f\u57fa\u672c\u7684\u306a3D\u30b7\u30fc\u30f3\uff08\u4e16\u754c\uff09\u3092\u69cb\u7bc9\u3059\u308b\u305f\u3081\u306e\u521d\u671f\u8a2d\u5b9a\u30b3\u30fc\u30c9\u3092\u8a18\u8ff0\u3057\u307e\u3059\u3002<br>3D\u30b7\u30fc\u30f3\u3092\u69cb\u7bc9\u3059\u308b\u305f\u3081\u306b\u3001\u307e\u305a\u4ee5\u4e0b\u306e3\u3064\u306e\u6838\u3068\u306a\u308b\u30e9\u30a4\u30c8\u3001\u5e8a\u3001\u58c1\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u5b9a\u7fa9\u3057\u90e8\u5c4b\u3092\u69cb\u7bc9\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<div class=\"wp-block-luxe-blocks-topic\" style=\"margin-top:10px;margin-bottom:30px\"><div class=\"wp-block-luxe-blocks-topic-title\" style=\"color:#fff;background-color:#006edc;border:1px solid #006edc;padding:2px 14px;align-items:center\">main.js\u8ffd\u52a0\u5185\u5bb9<\/div><div class=\"wp-block-luxe-blocks-topic-content\" style=\"border:1px solid #006edc;padding:0px 15px 0px 15px\">\n\n<ul type=\"1\">\n\n<li>\u30ec\u30a4\u30a2\u30a6\u30c8\u30c4\u30fc\u30eb\u306e\u57fa\u672c\u3068\u306a\u308b\u7a7a\u9593\u3092\u5b9a\u7fa9\u3057\u307e\u3059\u3002<\/li>\n\n\n<li>\/\/ === 1-5. \u30e9\u30a4\u30c8 (Light) \u306e\u8ffd\u52a0 ===<br>3D\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306f\u5149\u304c\u5f53\u305f\u3089\u306a\u3044\u3068\u771f\u3063\u9ed2(\u540c\u4e00\u8272)\u306b\u898b\u3048\u308b\u305f\u3081\u3001\u307e\u305a\u90e8\u5c4b\u5168\u4f53\u3092\u5747\u7b49\u306b\u7167\u3089\u3059\u74b0\u5883\u5149\u3092\u8ffd\u52a0\u3057\u307e\u3059\u3002<\/li>\n\n\n<li>\/\/ === 1-6 &amp; 1-7. \u90e8\u5c4b\u306e\u69cb\u9020\uff08\u5e8a\u3068\u58c1\uff09\u3068\u30b0\u30ea\u30c3\u30c9\u5b9a\u898f\u306e\u4f5c\u6210 ===<br>createRoomStructure()\u306e\u547c\u3073\u51fa\u3057<\/li>\n\n\n<li>createRoomStructure()\u95a2\u6570\u306e\u8ffd\u52a0\n\n<ul>\n\n<li>10m x 10m x 2m\u306e\u90e8\u5c4b\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/li>\n\n\n<li>\u8996\u899a\u7684\u5b9a\u898f(\u30b0\u30ea\u30c3\u30c9)\u306e\u8868\u793a<br>\u5e8a\u306b\u306f\u30b5\u30a4\u30ba\u304c\u5206\u304b\u308a\u3084\u3059\u3044\u3088\u3046\u306b\u3001THREE.GridHelper\u3092\u4f7f\u7528\u3057\u3066\uff11\uff4d\u9593\u9694\u306e\u8996\u899a\u7684\u5b9a\u898f(\u30b0\u30ea\u30c3\u30c9)\u3092\u8868\u793a\u3057\u3066\u3044\u307e\u3059\u3002<\/li>\n\n\n<li>\u58c1\u306e\u8868\u793a<br>THREE.BoxGeometry\u3067\u5358\u7d14\u306a\u76f4\u65b9\u4f53\u3067\u8868\u793a\u3057\u307e\u3059\u3002createWall()\u95a2\u6570\u30674\u3064\u306e\u58c1\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/li>\n\n\n<li>\u58c1\u306e\u900f\u660e\u5316<br>\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u914d\u7f6e\u3057\u305f\u5834\u6240\u306b\u3088\u3063\u3066\u96a0\u308c\u3066\u898b\u3048\u306a\u304f\u306a\u308b\u306e\u3092\u9632\u3050\u305f\u3081\u306b\u58c1\u3092\u534a\u900f\u660e\u5316\u3055\u305b\u3066\u304a\u304d\u307e\u3059\u3002THREE.MeshStandardMaterial\u306e\u30d1\u30e9\u30e1\u30fc\u30bf\u30fctransparent: true\u306b\u3088\u308a\u900f\u660e\u5316\u3067\u304d\u307e\u3059\u3002<\/li>\n\n<\/ul>\n\n<\/li>\n\n<\/ul>\n\n<\/div><\/div>\n\n\n\n<p>\u4ee5\u4e0b\u5909\u66f4\u3057\u305f<strong>main.js<\/strong>\u3092\u8a18\u8f09\u3057\u307e\u3059\u3002<strong>\u884c\u756a\u53f7\u6b04\u304c\u80cc\u666f\u8d64\u8272\u306e\u7b87\u6240<\/strong>\u304c\u4eca\u56de\u8ffd\u52a0\u3057\u305f\u30b3\u30fc\u30c9\u3067\u3059\u3002\uff08\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u304c\u9577\u3044\u306e\u3067\u30b9\u30af\u30ed\u30fc\u30eb\u3059\u308b\u3068\u53c2\u7167\u3067\u304d\u307e\u3059\uff09<\/p>\n\n\n<pre class=\"line-numbers highlight-code-room\"><code class=\"language-javascript\">\/\/ main.js\n\/\/ [main-001-room]\n\/\/ index.html \u306e importmap \u306e\u8a2d\u5b9a\u306b\u57fa\u3065\u304d\u3001\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\u3092\u30a4\u30f3\u30dd\u30fc\u30c8\nimport * as THREE from \"three\";\nimport { OrbitControls } from '.\/jsm\/controls\/OrbitControls.js';\n\n\/\/ \u5fc5\u8981\u306a\u5909\u6570\u3092\u30b0\u30ed\u30fc\u30d0\u30eb\u30b9\u30b3\u30fc\u30d7\u3067\u5b9a\u7fa9\nlet scene, camera, renderer, controls;\nlet roomGroup; \/\/ \u5e8a\u3001\u58c1\u3001\u5bb6\u5177\u3092\u307e\u3068\u3081\u308b\u30b0\u30eb\u30fc\u30d7\nconst roomSize = 10; \/\/ \u90e8\u5c4b\u306e\u30b5\u30a4\u30ba (10m x 10m)\nconst furniture = []; \/\/ \u8907\u6570\u306e\u5bb6\u5177\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u9806\u5e8f\u4ed8\u3051\u3057\u3066\u4fdd\u7ba1\n\/\/ 1. \u521d\u671f\u5316\u95a2\u6570\uff1a3D\u4e16\u754c\u306e\u571f\u53f0\u3092\u4f5c\u308b\nfunction init() {\n    \/\/ === 1-1. \u30b7\u30fc\u30f3 (Scene) \u306e\u4f5c\u6210 ===\n    scene = new THREE.Scene();\n    scene.background = new THREE.Color(0xf0f0f0); \/\/ \u80cc\u666f\u8272\u3092\u8584\u3044\u30b0\u30ec\u30fc\u306b\u8a2d\u5b9a\n    roomGroup = new THREE.Group();\n    scene.add(roomGroup);\n\n    \/\/ \u5ea7\u6a19\u8ef8\u30d8\u30eb\u30d1\u30fc\u3092\u8ffd\u52a0\uff08X\u8ef8\uff1a\u8d64\u3001Y\u8ef8\uff1a\u7dd1\u3001Z\u8ef8\uff1a\u9752\uff09\n    const axesHelper = new THREE.AxesHelper(10); \/\/ \u30b5\u30a4\u30ba10\n    scene.add(axesHelper);\n\n    \/\/ === 1-2. \u30ab\u30e1\u30e9 (Camera) \u306e\u8a2d\u5b9a ===\n    const fov = 75; \/\/ \u8996\u91ce\u89d2 (Field of View)\n    const aspect = window.innerWidth \/ window.innerHeight; \/\/ \u30a2\u30b9\u30da\u30af\u30c8\u6bd4\n    const near = 0.1; \/\/ \u63cf\u753b\u958b\u59cb\u8ddd\u96e2\n    const far = 1000; \/\/ \u63cf\u753b\u7d42\u4e86\u8ddd\u96e2\n    camera = new THREE.PerspectiveCamera(fov, aspect, near, far);\n    \n    \/\/ \u30ab\u30e1\u30e9\u306e\u521d\u671f\u4f4d\u7f6e\u3092\u6c7a\u5b9a (X, Y, Z)\n    camera.position.set(10, 15, 15);\n    camera.lookAt(0, 0, 0); \/\/ \u539f\u70b9(0, 0, 0)\u3092\u898b\u308b\u3088\u3046\u306b\u8a2d\u5b9a\n\n    \/\/ === 1-3. \u30ec\u30f3\u30c0\u30e9\u30fc (Renderer) \u306e\u4f5c\u6210 ===\n    renderer = new THREE.WebGLRenderer({ antialias: true }); \/\/ \u30a2\u30f3\u30c1\u30a8\u30a4\u30ea\u30a2\u30b9\u3067\u63cf\u753b\u3092\u6ed1\u3089\u304b\u306b\n    renderer.setSize(window.innerWidth, window.innerHeight); \/\/ \u63cf\u753b\u30b5\u30a4\u30ba\u3092\u30a6\u30a3\u30f3\u30c9\u30a6\u30b5\u30a4\u30ba\u306b\u5408\u308f\u305b\u308b\n    renderer.outputEncoding = THREE.sRGBEncoding; \/\/ \u30ec\u30f3\u30c0\u30ea\u30f3\u30b0\u54c1\u8cea\u6539\u5584\n    renderer.shadowMap.enabled = true; \/\/ \u5f71\u306e\u63cf\u753b\u3092\u6709\u52b9\u5316\n\n    \/\/ \u751f\u6210\u3055\u308c\u305f&lt;canvas&gt;\u8981\u7d20\u3092HTML&lt;body&gt;\u306b\u8ffd\u52a0\n    document.body.appendChild(renderer.domElement);\n\n    \/\/ === 1-4. \u30ab\u30e1\u30e9\u64cd\u4f5c (OrbitControls) \u306e\u8a2d\u5b9a ===\n    \/\/ \u30a4\u30f3\u30dd\u30fc\u30c8\u3057\u305f OrbitControls \u3092\u4f7f\u3063\u3066\u3001\u30de\u30a6\u30b9\u3067\u30ab\u30e1\u30e9\u3092\u52d5\u304b\u305b\u308b\u3088\u3046\u306b\u3059\u308b\n    controls = new OrbitControls(camera, renderer.domElement);\n    controls.enableDamping = true; \/\/ \u52d5\u304d\u3092\u6ed1\u3089\u304b\u306b\u3059\u308b\n    controls.dampingFactor = 0.05;\n\n    \/\/ === 1-5. \u30e9\u30a4\u30c8 (Lighting) \u306e\u8ffd\u52a0 ===\n    \/\/ \u90e8\u5c4b\u5168\u4f53\u3092\u5747\u7b49\u306b\u7167\u3089\u3059\u74b0\u5883\u5149\n    const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); \/\/ \u5f31\u3081\u306e\u5149\n    scene.add(ambientLight);\n\n    \/\/ \u7279\u5b9a\u306e\u65b9\u5411\u304b\u3089\u7167\u3089\u3059\u6307\u5411\u6027\u5149\uff08\u5f71\u3092\u843d\u3068\u3059\u305f\u3081\u306b\u5fc5\u8981\uff09\n    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);\n    directionalLight.position.set(20, 30, 10);\n    scene.add(directionalLight);\n\n    \/\/ === 1-6 &amp; 1-7. \u90e8\u5c4b\u306e\u69cb\u9020\uff08\u5e8a\u3068\u58c1\uff09\u3068\u30b0\u30ea\u30c3\u30c9\u5b9a\u898f\u306e\u4f5c\u6210 ===\n    createRoomStructure();\n    \/\/ \u30a6\u30a3\u30f3\u30c9\u30a6\u30b5\u30a4\u30ba\u304c\u5909\u66f4\u3055\u308c\u305f\u3068\u304d\u306e\u30ea\u30b5\u30a4\u30ba\u51e6\u7406\u3092\u767b\u9332\n    window.addEventListener('resize', onWindowResize, false);\n}\n\n\/\/ 2. \u63cf\u753b\u30eb\u30fc\u30d7\u95a2\u6570\uff1a\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u306e\u5fc3\u81d3\u90e8\nfunction animate() {\n    requestAnimationFrame(animate); \/\/ \u30d6\u30e9\u30a6\u30b6\u306e\u518d\u63cf\u753b\u30bf\u30a4\u30df\u30f3\u30b0\u306b\u5408\u308f\u305b\u3066\u30eb\u30fc\u30d7\u3092\u7d99\u7d9a\n    controls.update(); \/\/ \u30ab\u30e1\u30e9\u64cd\u4f5c\u306e\u30c0\u30f3\u30d4\u30f3\u30b0\u52b9\u679c\u3092\u9069\u7528\u3059\u308b\u305f\u3081\u306b\u66f4\u65b0\u304c\u5fc5\u8981\n    renderer.render(scene, camera); \/\/ \u30b7\u30fc\u30f3\u3092\u30ab\u30e1\u30e9\u306e\u8996\u70b9\u304b\u3089\u63cf\u753b\n}\n\n\/\/ 3. \u30a6\u30a3\u30f3\u30c9\u30a6\u30ea\u30b5\u30a4\u30ba\u51e6\u7406\uff1a\u753b\u9762\u30b5\u30a4\u30ba\u304c\u5909\u308f\u3063\u3066\u3082\u8868\u793a\u3092\u6700\u9069\u5316\nfunction onWindowResize() {\n    camera.aspect = window.innerWidth \/ window.innerHeight;    \/\/ \u30ab\u30e1\u30e9\u306e\u30a2\u30b9\u30da\u30af\u30c8\u6bd4\u66f4\u65b0\n    camera.updateProjectionMatrix(); \/\/ \u30ab\u30e1\u30e9\u306e\u6295\u5f71\u884c\u5217\u3092\u66f4\u65b0\n    renderer.setSize(window.innerWidth, window.innerHeight); \/\/ \u30ec\u30f3\u30c0\u30e9\u30fc\u306e\u30b5\u30a4\u30ba\u66f4\u65b0\n}\n\n\/\/ 4. \u90e8\u5c4b\u5168\u4f53\u69cb\u9020\u306e\u4f5c\u6210\nfunction createRoomStructure() {\n    const wallHeight = 2; \n\n    \/\/ \u5e8a\u306e\u4f5c\u6210\n    const floorGeometry = new THREE.PlaneGeometry(roomSize, roomSize); \n    const floorMaterial = new THREE.MeshStandardMaterial({ \n        color: 0xf8feff,\n        side: THREE.DoubleSide\n    });\n    const floor = new THREE.Mesh(floorGeometry, floorMaterial);\n    floor.rotation.x = Math.PI \/ 2;\n    floor.position.y = 0; \n    floor.receiveShadow = true; \n    roomGroup.add(floor); \n    \n    \/\/ \u8996\u899a\u7684\u5b9a\u898f\uff08GridHelper\uff09\u306e\u8ffd\u52a0 (1m\u9593\u9694)\n    const gridHelper = new THREE.GridHelper(\n        roomSize, roomSize, 0x444444, 0x888888        \n    );\n    gridHelper.position.y = 0.01; \n    roomGroup.add(gridHelper); \n\n    \/\/ \u58c1\u306e\u534a\u900f\u660e\u30de\u30c6\u30ea\u30a2\u30eb\u3092\u4f5c\u6210 \n    const wallMaterial = new THREE.MeshStandardMaterial({ \n        color: 0xf0e68c, \n        transparent: true, \n        opacity: 0.3,      \n        side: THREE.DoubleSide \n    });\n    \n    \/\/ \u58c1\u306e\u4f5c\u6210\u30d8\u30eb\u30d1\u30fc\n    function createWall(x, z, length, height, rotationY) {\n        const wallGeometry = new THREE.BoxGeometry(length, height, 0.1); \n        const wall = new THREE.Mesh(wallGeometry, wallMaterial); \n        \n        wall.position.y = height \/ 2;\n        wall.position.x = x;\n        wall.position.z = z;\n        wall.rotation.y = rotationY;\n        wall.receiveShadow = true;\n        roomGroup.add(wall); \n    }\n    \n    \/\/ 4\u3064\u306e\u58c1\u3092\u4f5c\u6210\n    createWall(0, -roomSize \/ 2, roomSize, wallHeight, 0); \n    createWall(0, roomSize \/ 2, roomSize, wallHeight, 0); \n    createWall(-roomSize \/ 2, 0, roomSize, wallHeight, Math.PI \/ 2); \n    createWall(roomSize \/ 2, 0, roomSize, wallHeight, Math.PI \/ 2); \n}\n\n\/\/ \u5b9f\u884c\ninit();\nanimate();\n\n<\/code><\/pre>\n\n\n<p>\u3053\u308c\u3067\u660e\u308b\u3044\u5e8a\u30684\u3064\u306e\u58c1\u3067\u69cb\u6210\u3055\u308c\u305f\u30b7\u30f3\u30d7\u30eb\u306a\u7bb1\u578b\u306e\u90e8\u5c4b\u304c\u8868\u793a\u3055\u308c\u307e\u3059\u3002\u30ec\u30a4\u30a2\u30a6\u30c8\u3092\u884c\u3046\u305f\u3081\u306e\u7a7a\u9593\u304c\u5b8c\u6210\u3067\u3059\u3002\u90e8\u5c4b\u3092\u30de\u30a6\u30b9\u306e\u5de6\u30af\u30ea\u30c3\u30af\u3067\u56de\u8ee2\u3001\u53f3\u30af\u30ea\u30c3\u30af\u3067\u79fb\u52d5\u3001\u30db\u30a4\u30fc\u30eb\u3067\u30ba\u30fc\u30e0\u304c\u3067\u304d\u308b\u3088\u3046\u306b\u306a\u3063\u3066\u3044\u308b\u306f\u305a\u3067\u3059\u3002<br><img decoding=\"async\" class=\"wp-image-49225\" style=\"width: 640px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-8.png\" alt=\"VS Code\u5b9f\u884c\u7d50\u679c\u30fc\u90e8\u5c4b\u8868\u793a\u306e\u78ba\u8a8d\"><br>\u203b\u4fdd\u5b58\u3068\u623b\u3059\u30dc\u30bf\u30f3\u304c\u8868\u793a\u3055\u308c\u3066\u3044\u307e\u3059\u304c\u3001\u8868\u793a\u306e\u307f\u3067\u3053\u306e\u6bb5\u968e\u3067\u306f\u6a5f\u80fd\u3057\u3066\u3044\u307e\u305b\u3093\u3002\u3053\u306e\u6a5f\u80fd\u306f\u6700\u5f8c\u306b\u8ffd\u52a0\u3057\u307e\u3059\u3002<br>\u4eca\u5f8c\u3001<strong>createRoomStructure()<\/strong>\u3067\u4f5c\u6210\u3057\u305fTHREE.js \u30b0\u30eb\u30fc\u30d7\u30aa\u30d6\u30b8\u30a7\u30af\u30c8<strong>roomGroup<\/strong>\u306b\u5bfe\u3057\u3066\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u8ffd\u52a0\u3001\u64cd\u4f5c\u3092\u3057\u3066\u3044\u304f\u3053\u3068\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u5bb6\u5177\uff08\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\uff09\u306e\u4f5c\u6210<\/h3>\n\n\n\n<p>\u90e8\u5c4b\u306e\u69cb\u9020\u304c\u3067\u304d\u305f\u306e\u3067\u3001\u6b21\u306b\u30ec\u30a4\u30a2\u30a6\u30c8\u306e\u4e2d\u5fc3\u3068\u306a\u308b\u5bb6\u5177\u306e\u30d7\u30ec\u30fc\u30b9\u30db\u30eb\u30c0\u30fc\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002\u3053\u3053\u3067\u306f\u3001\u57fa\u672c\u7684\u306a\u5f62\u72b6\u3067\u3042\u308bTHREE.BoxGeometry\u3092\u4f7f\u3063\u3066\u3001\u76f4\u65b9\u4f53\u3067\u8868\u73fe\u3057\u305f\u30c7\u30b9\u30af\u3068\u6905\u5b50\u3001\u68da\u3092\u914d\u7f6e\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<div class=\"wp-block-luxe-blocks-topic\" style=\"margin-top:10px;margin-bottom:30px\"><div class=\"wp-block-luxe-blocks-topic-title\" style=\"color:#fff;background-color:#006edc;border:1px solid #006edc;padding:2px 14px;align-items:center\">main.js \u8ffd\u52a0\u5185\u5bb9<\/div><div class=\"wp-block-luxe-blocks-topic-content\" style=\"border:1px solid #006edc;padding:0px 15px 0px 15px\">\n\n<ul type=\"1\">\n\n<li>\/\/=== 1-8. \u5bb6\u5177\uff08\u30d7\u30ec\u30fc\u30b9\u30db\u30eb\u30c0\u30fc\uff09\u306e\u4f5c\u6210\u3068\u914d\u7f6e ===<br>\u30b5\u30a4\u30ba\u8a2d\u5b9a\u3068addFurniture()\u95a2\u6570\u306e\u547c\u3073\u51fa\u3057<\/li>\n\n\n<li>addFurniture()\u95a2\u6570\u306e\u8ffd\u52a0<br>\u76f4\u65b9\u4f53\u306e\u5f62\u72b6\u3092THREE.BoxGeometry()\u3001THREE.MeshStandardMaterial()\u3067THREE.Mesh\u306b\u3057\u307e\u3059\u3002\u4f5c\u6210\u3057\u305fMesh\u3092roomGroup.add()\u3067\u90e8\u5c4b\u306b\u8a2d\u7f6e\u3057\u307e\u3059\u3002<\/li>\n\n<\/ul>\n\n<\/div><\/div>\n\n\n<pre class=\"line-numbers highlight-code-furniture\"><code class=\"language-javascript\">\/\/ main.js\n\/\/ [main-002-object]\n\/\/ index.html \u306e importmap \u306e\u8a2d\u5b9a\u306b\u57fa\u3065\u304d\u3001\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\u3092\u30a4\u30f3\u30dd\u30fc\u30c8\nimport * as THREE from \"three\";\nimport { OrbitControls } from '.\/jsm\/controls\/OrbitControls.js';\n\n\/\/ \u5fc5\u8981\u306a\u5909\u6570\u3092\u30b0\u30ed\u30fc\u30d0\u30eb\u30b9\u30b3\u30fc\u30d7\u3067\u5b9a\u7fa9\nlet scene, camera, renderer, controls;\nlet roomGroup; \/\/ \u5e8a\u3001\u58c1\u3001\u5bb6\u5177\u3092\u307e\u3068\u3081\u308b\u30b0\u30eb\u30fc\u30d7\n\nconst roomSize = 10; \/\/ \u90e8\u5c4b\u306e\u30b5\u30a4\u30ba (10m x 10m)\nconst furniture = []; \/\/ \u8907\u6570\u306e\u5bb6\u5177\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u9806\u5e8f\u4ed8\u3051\u3057\u3066\u4fdd\u7ba1\n\n\/\/ 1. \u521d\u671f\u5316\u95a2\u6570\uff1a3D\u4e16\u754c\u306e\u571f\u53f0\u3092\u4f5c\u308b\nfunction init() {\n    \/\/ === 1-1. \u30b7\u30fc\u30f3 (Scene) \u306e\u4f5c\u6210 ===\n    scene = new THREE.Scene();\n    scene.background = new THREE.Color(0xf0f0f0); \/\/ \u80cc\u666f\u8272\u3092\u8584\u3044\u30b0\u30ec\u30fc\u306b\u8a2d\u5b9a\n    roomGroup = new THREE.Group();\n    scene.add(roomGroup);\n\n    \/\/ \u5ea7\u6a19\u8ef8\u30d8\u30eb\u30d1\u30fc\u3092\u8ffd\u52a0\uff08X\u8ef8\uff1a\u8d64\u3001Y\u8ef8\uff1a\u7dd1\u3001Z\u8ef8\uff1a\u9752\uff09\n    const axesHelper = new THREE.AxesHelper(10); \/\/ \u30b5\u30a4\u30ba10\n    scene.add(axesHelper);\n\n    \/\/ === 1-2. \u30ab\u30e1\u30e9 (Camera) \u306e\u8a2d\u5b9a ===\n    const fov = 75; \/\/ \u8996\u91ce\u89d2 (Field of View)\n    const aspect = window.innerWidth \/ window.innerHeight; \/\/ \u30a2\u30b9\u30da\u30af\u30c8\u6bd4\n    const near = 0.1; \/\/ \u63cf\u753b\u958b\u59cb\u8ddd\u96e2\n    const far = 1000; \/\/ \u63cf\u753b\u7d42\u4e86\u8ddd\u96e2\n    camera = new THREE.PerspectiveCamera(fov, aspect, near, far);\n    \n    \/\/ \u30ab\u30e1\u30e9\u306e\u521d\u671f\u4f4d\u7f6e\u3092\u6c7a\u5b9a (X, Y, Z)\n    camera.position.set(10, 15, 15);\n    camera.lookAt(0, 0, 0); \/\/ \u539f\u70b9(0, 0, 0)\u3092\u898b\u308b\u3088\u3046\u306b\u8a2d\u5b9a\n\n    \/\/ === 1-3. \u30ec\u30f3\u30c0\u30e9\u30fc (Renderer) \u306e\u4f5c\u6210 ===\n    renderer = new THREE.WebGLRenderer({ antialias: true }); \/\/ \u30a2\u30f3\u30c1\u30a8\u30a4\u30ea\u30a2\u30b9\u3067\u63cf\u753b\u3092\u6ed1\u3089\u304b\u306b\n    renderer.setSize(window.innerWidth, window.innerHeight); \/\/ \u63cf\u753b\u30b5\u30a4\u30ba\u3092\u30a6\u30a3\u30f3\u30c9\u30a6\u30b5\u30a4\u30ba\u306b\u5408\u308f\u305b\u308b\n    renderer.outputEncoding = THREE.sRGBEncoding; \/\/ \u30ec\u30f3\u30c0\u30ea\u30f3\u30b0\u54c1\u8cea\u6539\u5584\n    renderer.shadowMap.enabled = true; \/\/ \u5f71\u306e\u63cf\u753b\u3092\u6709\u52b9\u5316\n\n    \/\/ \u751f\u6210\u3055\u308c\u305f&lt;canvas&gt;\u8981\u7d20\u3092HTML&lt;body&gt;\u306b\u8ffd\u52a0\n    document.body.appendChild(renderer.domElement);\n\n    \/\/ === 1-4. \u30ab\u30e1\u30e9\u64cd\u4f5c (OrbitControls) \u306e\u8a2d\u5b9a ===\n    \/\/ \u30a4\u30f3\u30dd\u30fc\u30c8\u3057\u305f OrbitControls \u3092\u4f7f\u3063\u3066\u3001\u30de\u30a6\u30b9\u3067\u30ab\u30e1\u30e9\u3092\u52d5\u304b\u305b\u308b\u3088\u3046\u306b\u3059\u308b\n    controls = new OrbitControls(camera, renderer.domElement);\n    controls.enableDamping = true; \/\/ \u52d5\u304d\u3092\u6ed1\u3089\u304b\u306b\u3059\u308b\n    controls.dampingFactor = 0.05;\n\n    \/\/ === 1-5. \u30e9\u30a4\u30c8 (Lighting) \u306e\u8ffd\u52a0 ===\n    \/\/ \u90e8\u5c4b\u5168\u4f53\u3092\u5747\u7b49\u306b\u7167\u3089\u3059\u74b0\u5883\u5149\n    const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); \/\/ \u5f31\u3081\u306e\u5149\n    scene.add(ambientLight);\n\n    \/\/ \u7279\u5b9a\u306e\u65b9\u5411\u304b\u3089\u7167\u3089\u3059\u6307\u5411\u6027\u5149\uff08\u5f71\u3092\u843d\u3068\u3059\u305f\u3081\u306b\u5fc5\u8981\uff09\n    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);\n    directionalLight.position.set(20, 30, 10);\n    scene.add(directionalLight);\n\n    \/\/ === 1-6 &amp; 1-7. \u90e8\u5c4b\u306e\u69cb\u9020\uff08\u5e8a\u3068\u58c1\uff09\u3068\u30b0\u30ea\u30c3\u30c9\u5b9a\u898f\u306e\u4f5c\u6210 ===\n    createRoomStructure();\n\n    \/\/ === 1-8. \u5bb6\u5177\uff08\u30d7\u30ec\u30fc\u30b9\u30db\u30eb\u30c0\u30fc\uff09\u306e\u4f5c\u6210\u3068\u914d\u7f6e ===\n    \/\/ \u5bb6\u5177\u306e\u914d\u7f6e\u4f8b\n    const deskHeight = 0.75;\n    const chairHeight = 0.5;\n\n    addFurniture(2, 2, 1, 3, 2.0, 0xa0522d); \/\/ \u68da\n    addFurniture(-3, -3, 3, 1.5, deskHeight, 0xdeb887); \/\/ \u30c7\u30b9\u30af\n    addFurniture(-3, -1, 0.5, 0.5, chairHeight, 0x800000); \/\/ \u30c1\u30a7\u30a2\n    \n    \/\/ \u30a6\u30a3\u30f3\u30c9\u30a6\u30b5\u30a4\u30ba\u304c\u5909\u66f4\u3055\u308c\u305f\u3068\u304d\u306e\u30ea\u30b5\u30a4\u30ba\u51e6\u7406\u3092\u767b\u9332\n    window.addEventListener('resize', onWindowResize, false);\n}\n\n\/\/ 2. \u63cf\u753b\u30eb\u30fc\u30d7\u95a2\u6570\uff1a\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u306e\u5fc3\u81d3\u90e8\nfunction animate() {\n    requestAnimationFrame(animate); \/\/ \u30d6\u30e9\u30a6\u30b6\u306e\u518d\u63cf\u753b\u30bf\u30a4\u30df\u30f3\u30b0\u306b\u5408\u308f\u305b\u3066\u30eb\u30fc\u30d7\u3092\u7d99\u7d9a\n    controls.update(); \/\/ \u30ab\u30e1\u30e9\u64cd\u4f5c\u306e\u30c0\u30f3\u30d4\u30f3\u30b0\u52b9\u679c\u3092\u9069\u7528\u3059\u308b\u305f\u3081\u306b\u66f4\u65b0\u304c\u5fc5\u8981\n    renderer.render(scene, camera); \/\/ \u30b7\u30fc\u30f3\u3092\u30ab\u30e1\u30e9\u306e\u8996\u70b9\u304b\u3089\u63cf\u753b\n}\n\n\/\/ 3. \u30a6\u30a3\u30f3\u30c9\u30a6\u30ea\u30b5\u30a4\u30ba\u51e6\u7406\uff1a\u753b\u9762\u30b5\u30a4\u30ba\u304c\u5909\u308f\u3063\u3066\u3082\u8868\u793a\u3092\u6700\u9069\u5316\nfunction onWindowResize() {\n    camera.aspect = window.innerWidth \/ window.innerHeight;    \/\/ \u30ab\u30e1\u30e9\u306e\u30a2\u30b9\u30da\u30af\u30c8\u6bd4\u66f4\u65b0\n    camera.updateProjectionMatrix(); \/\/ \u30ab\u30e1\u30e9\u306e\u6295\u5f71\u884c\u5217\u3092\u66f4\u65b0\n    renderer.setSize(window.innerWidth, window.innerHeight); \/\/ \u30ec\u30f3\u30c0\u30e9\u30fc\u306e\u30b5\u30a4\u30ba\u66f4\u65b0\n}\n\n\/\/ 4. \u90e8\u5c4b\u5168\u4f53\u69cb\u9020\u306e\u4f5c\u6210\nfunction createRoomStructure() {\n    const wallHeight = 2; \n\n    \/\/ \u5e8a\u306e\u4f5c\u6210\n    const floorGeometry = new THREE.PlaneGeometry(roomSize, roomSize); \n    const floorMaterial = new THREE.MeshStandardMaterial({ \n        color: 0xf8feff,\n        side: THREE.DoubleSide\n    });\n    const floor = new THREE.Mesh(floorGeometry, floorMaterial);\n    floor.rotation.x = Math.PI \/ 2;\n    floor.position.y = 0; \n    floor.receiveShadow = true; \n    roomGroup.add(floor); \n    \n    \/\/ \u8996\u899a\u7684\u5b9a\u898f\uff08GridHelper\uff09\u306e\u8ffd\u52a0 (1m\u9593\u9694)\n    const gridHelper = new THREE.GridHelper(\n        roomSize, roomSize, 0x444444, 0x888888        \n    );\n    gridHelper.position.y = 0.01; \n    roomGroup.add(gridHelper); \n\n    \/\/ \u58c1\u306e\u534a\u900f\u660e\u30de\u30c6\u30ea\u30a2\u30eb\u3092\u4f5c\u6210 \n    const wallMaterial = new THREE.MeshStandardMaterial({ \n        color: 0xf0e68c, \n        transparent: true, \n        opacity: 0.3,      \n        side: THREE.DoubleSide \n    });\n    \n    \/\/ \u58c1\u306e\u4f5c\u6210\u30d8\u30eb\u30d1\u30fc\n    function createWall(x, z, length, height, rotationY) {\n        const wallGeometry = new THREE.BoxGeometry(length, height, 0.1); \n        const wall = new THREE.Mesh(wallGeometry, wallMaterial); \n        \n        wall.position.y = height \/ 2;\n        wall.position.x = x;\n        wall.position.z = z;\n        wall.rotation.y = rotationY;\n        wall.receiveShadow = true;\n        roomGroup.add(wall); \n    }\n    \n    \/\/ 4\u3064\u306e\u58c1\u3092\u4f5c\u6210\n    createWall(0, -roomSize \/ 2, roomSize, wallHeight, 0); \n    createWall(0, roomSize \/ 2, roomSize, wallHeight, 0); \n    createWall(-roomSize \/ 2, 0, roomSize, wallHeight, Math.PI \/ 2); \n    createWall(roomSize \/ 2, 0, roomSize, wallHeight, Math.PI \/ 2); \n}\n\n\/\/ 5.\u5358\u7d14\u306a\u5bb6\u5177\uff08BoxGeometry\uff09\u3092\u8ffd\u52a0\u3059\u308b\nfunction addFurniture(x, z, width, depth, height, color) {\n    \/\/ BoxGeometry: \u7acb\u65b9\u4f53\/\u76f4\u65b9\u4f53\u306e\u5f62\u72b6\n    const geometry = new THREE.BoxGeometry(width, height, depth); \n    const material = new THREE.MeshStandardMaterial({ color: color });\n    const mesh = new THREE.Mesh(geometry, material);\n    \/\/ \u5bb6\u5177\u306eY\u8ef8\u306e\u4f4d\u7f6e\u3092\u5e8a\u304b\u3089\u534a\u5206\u306e\u9ad8\u3055\u306b\u8a2d\u5b9a\n    mesh.position.set(x, height \/ 2, z); \n    mesh.castShadow = true; \n    mesh.receiveShadow = true; \n    \/\/ ID\u3092\u8a2d\u5b9a\u3057\u3001\u4fdd\u5b58\u30fb\u8aad\u307f\u8fbc\u307f\u6642\u306b\u4e00\u8cab\u6027\u3092\u4fdd\u3064\n    mesh.userData.draggable = true;\n    mesh.userData.id = furniture.length; \n    \/\/ \u3053\u306e\u30e1\u30c3\u30b7\u30e5\u304c\u5f8c\u306bRaycaster\u306b\u3088\u308b\u9078\u629e\u306e\u5bfe\u8c61\u3068\u306a\u308b\u3088\u3046\u306b\u8a2d\u5b9a\n    mesh.userData.name = `furniture_${mesh.userData.id}`;\n    \n    roomGroup.add(mesh);  \/\/ roomGroup\u306b\u8ffd\u52a0\n    furniture.push(mesh); \/\/ \u5bb6\u5177\u306e\u4f4d\u7f6e\u72b6\u614b\u3092\u4fdd\u7ba1\n    \n    return mesh;\n}\n\n\/\/ \u5b9f\u884c\ninit();\nanimate();\n\n<\/code><\/pre>\n\n\n<ul type=\"1\">\n<li>addFurniture()\u95a2\u6570\u3067\u76f4\u65b9\u4f53\u306e\u5f62\u72b6\u3092THREE.BoxGeometry()\u3001THREE.MeshStandardMaterial()\u3067THREE.Mesh\u306b\u3057\u307e\u3059\u3002<\/li>\n\n\n\n<li>\u4f5c\u6210\u3057\u305fMesh\u3092roomGroup.add()\u3067\u90e8\u5c4b\u306b\u8a2d\u7f6e\u3057\u307e\u3059\u3002<\/li>\n<\/ul>\n\n\n\n<p><img decoding=\"async\" class=\"wp-image-49229\" style=\"width: 640px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-10.png\" alt=\"VS Code\u5b9f\u884c\u7d50\u679c\u30fc\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u8868\u793a\u306e\u78ba\u8a8d\"><\/p>\n\n\n\n<p>\u5bb6\u5177\u304c\u914d\u7f6e\u3055\u308c\u3066\u3044\u308b\u304b\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002<br>THREE.DirectionalLight\u306b\u3088\u3063\u3066\u76f4\u65b9\u4f53\u306e\uff13\u9762\u306b\u5149\u304c\u5f53\u305f\u3063\u3066\u5404\u9762\u304c\u8a8d\u8b58\u3067\u304d\u307e\u3059\u3002\u3053\u308c\u3092\u8a2d\u5b9a\u3057\u306a\u3044\u3068\u5404\u9762\u304c\u540c\u4e00\u8272\u306b\u306a\u308a\u7acb\u4f53\u3067\u3042\u308b\u3053\u3068\u304c\u5224\u5225\u3067\u304d\u307e\u305b\u3093\u3002<\/p>\n\n\n\n<p>\u307e\u305f\u5149\u6e90\u306e\u8a2d\u5b9a\u3092\u3057\u307e\u3057\u305f\u304c\u5e8a\u306b\u5f71\u306f\u6295\u5f71\u3055\u308c\u307e\u305b\u3093\u3002\u5f8c\u3067\u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u3092\u8a2d\u7f6e\u3057\u3066\u5f71\u3082\u6295\u5f71\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u30b0\u30eb\u30fc\u30d7\u5316\u3057\u3066\u6905\u5b50\u306e\u4f5c\u6210<\/h3>\n\n\n\n<p>\u6905\u5b50\u3068\u3044\u3063\u3066\u3082\u76f4\u65b9\u4f53\u3067\u3059\u306e\u3067\u3001\u6905\u5b50\u3089\u3057\u304f\u3059\u308b\u305f\u3081\u306b\u7c21\u5358\u306a\u65b9\u6cd5\u3068\u3057\u3066\u8907\u6570\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u4e00\u3064\u306b\u3057\u3066\u6905\u5b50\u3092\u8868\u73fe\u3057\u3066\u307f\u307e\u3059\u3002<\/p>\n\n\n\n<div class=\"wp-block-luxe-blocks-topic\" style=\"margin-top:10px;margin-bottom:30px\"><div class=\"wp-block-luxe-blocks-topic-title\" style=\"color:#fff;background-color:#006edc;border:1px solid #006edc;padding:2px 14px;align-items:center\">main.js \u8ffd\u52a0\u5185\u5bb9<\/div><div class=\"wp-block-luxe-blocks-topic-content\" style=\"border:1px solid #006edc;padding:0px 15px 0px 15px\">\n\n<ul type=\"1\">\n\n<li>\/\/ === 1-8. \u5bb6\u5177\uff08\u30d7\u30ec\u30fc\u30b9\u30db\u30eb\u30c0\u30fc\uff09\u306e\u4f5c\u6210\u3068\u914d\u7f6e ===<br>addFurniture(-3, -1, 0.5, 0.5, chairHeight, 0x800000);\u3092\u30b3\u30e1\u30f3\u30c8\u30a2\u30a6\u30c8\u3057\u3001addChair()\u95a2\u6570\u3067\u8907\u6570\u306e\u76f4\u65b9\u4f53\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u7d44\u307f\u5408\u308f\u305b\u3066\u6905\u5b50\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u914d\u7f6e\u306f\u3053\u308c\u307e\u3067\u3068\u540c\u69d8\u306broomGroup.add()\u3067\u8ffd\u52a0\u3057\u307e\u3059\u3002<\/li>\n\n\n<li>addChair()\u95a2\u6570\u306e\u8ffd\u52a0<br>THREE.Group\u306e\u5c0e\u5165: \u6905\u5b50\u3092\u69cb\u6210\u3059\u308b\u5ea7\u9762\u3001\u80cc\u3082\u305f\u308c\u30014\u672c\u306e\u811a\u3092\u305d\u308c\u305e\u308cTHREE.Mesh\u3068\u3057\u3066\u4f5c\u6210\u3057\u3001\u305d\u308c\u3089\u3092\u4e00\u3064\u306eTHREE.Group\u306b\u307e\u3068\u3081\u307e\u3059\u3002<\/li>\n\n<\/ul>\n\n<\/div><\/div>\n\n\n<pre class=\"line-numbers highlight-code-chair\"><code class=\"language-javascript\">\/\/ main.js\n\/\/ [main-003-objects]\n\/\/ index.html \u306e importmap \u306e\u8a2d\u5b9a\u306b\u57fa\u3065\u304d\u3001\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\u3092\u30a4\u30f3\u30dd\u30fc\u30c8\nimport * as THREE from \"three\";\nimport { OrbitControls } from '.\/jsm\/controls\/OrbitControls.js';\n\n\/\/ \u5fc5\u8981\u306a\u5909\u6570\u3092\u30b0\u30ed\u30fc\u30d0\u30eb\u30b9\u30b3\u30fc\u30d7\u3067\u5b9a\u7fa9\nlet scene, camera, renderer, controls;\nlet roomGroup; \/\/ \u5e8a\u3001\u58c1\u3001\u5bb6\u5177\u3092\u307e\u3068\u3081\u308b\u30b0\u30eb\u30fc\u30d7\n\nconst roomSize = 10; \/\/ \u90e8\u5c4b\u306e\u30b5\u30a4\u30ba (10m x 10m)\nconst furniture = []; \/\/ \u8907\u6570\u306e\u5bb6\u5177\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u9806\u5e8f\u4ed8\u3051\u3057\u3066\u4fdd\u7ba1\n\n\/\/ 1. \u521d\u671f\u5316\u95a2\u6570\uff1a3D\u4e16\u754c\u306e\u571f\u53f0\u3092\u4f5c\u308b\nfunction init() {\n    \/\/ === 1-1. \u30b7\u30fc\u30f3 (Scene) \u306e\u4f5c\u6210 ===\n    scene = new THREE.Scene();\n    scene.background = new THREE.Color(0xf0f0f0); \/\/ \u80cc\u666f\u8272\u3092\u8584\u3044\u30b0\u30ec\u30fc\u306b\u8a2d\u5b9a\n    roomGroup = new THREE.Group();\n    scene.add(roomGroup);\n\n    \/\/ \u5ea7\u6a19\u8ef8\u30d8\u30eb\u30d1\u30fc\u3092\u8ffd\u52a0\uff08X\u8ef8\uff1a\u8d64\u3001Y\u8ef8\uff1a\u7dd1\u3001Z\u8ef8\uff1a\u9752\uff09\n    const axesHelper = new THREE.AxesHelper(10); \/\/ \u30b5\u30a4\u30ba10\n    scene.add(axesHelper);\n\n    \/\/ === 1-2. \u30ab\u30e1\u30e9 (Camera) \u306e\u8a2d\u5b9a ===\n    const fov = 75; \/\/ \u8996\u91ce\u89d2 (Field of View)\n    const aspect = window.innerWidth \/ window.innerHeight; \/\/ \u30a2\u30b9\u30da\u30af\u30c8\u6bd4\n    const near = 0.1; \/\/ \u63cf\u753b\u958b\u59cb\u8ddd\u96e2\n    const far = 1000; \/\/ \u63cf\u753b\u7d42\u4e86\u8ddd\u96e2\n    camera = new THREE.PerspectiveCamera(fov, aspect, near, far);\n    \n    \/\/ \u30ab\u30e1\u30e9\u306e\u521d\u671f\u4f4d\u7f6e\u3092\u6c7a\u5b9a (X, Y, Z)\n    camera.position.set(10, 15, 15);\n    camera.lookAt(0, 0, 0); \/\/ \u539f\u70b9(0, 0, 0)\u3092\u898b\u308b\u3088\u3046\u306b\u8a2d\u5b9a\n\n    \/\/ === 1-3. \u30ec\u30f3\u30c0\u30e9\u30fc (Renderer) \u306e\u4f5c\u6210 ===\n    renderer = new THREE.WebGLRenderer({ antialias: true }); \/\/ \u30a2\u30f3\u30c1\u30a8\u30a4\u30ea\u30a2\u30b9\u3067\u63cf\u753b\u3092\u6ed1\u3089\u304b\u306b\n    renderer.setSize(window.innerWidth, window.innerHeight); \/\/ \u63cf\u753b\u30b5\u30a4\u30ba\u3092\u30a6\u30a3\u30f3\u30c9\u30a6\u30b5\u30a4\u30ba\u306b\u5408\u308f\u305b\u308b\n    renderer.outputEncoding = THREE.sRGBEncoding; \/\/ \u30ec\u30f3\u30c0\u30ea\u30f3\u30b0\u54c1\u8cea\u6539\u5584\n    renderer.shadowMap.enabled = true; \/\/ \u5f71\u306e\u63cf\u753b\u3092\u6709\u52b9\u5316\n\n    \/\/ \u751f\u6210\u3055\u308c\u305f&lt;canvas&gt;\u8981\u7d20\u3092HTML&lt;body&gt;\u306b\u8ffd\u52a0\n    document.body.appendChild(renderer.domElement);\n\n    \/\/ === 1-4. \u30ab\u30e1\u30e9\u64cd\u4f5c (OrbitControls) \u306e\u8a2d\u5b9a ===\n    \/\/ \u30a4\u30f3\u30dd\u30fc\u30c8\u3057\u305f OrbitControls \u3092\u4f7f\u3063\u3066\u3001\u30de\u30a6\u30b9\u3067\u30ab\u30e1\u30e9\u3092\u52d5\u304b\u305b\u308b\u3088\u3046\u306b\u3059\u308b\n    controls = new OrbitControls(camera, renderer.domElement);\n    controls.enableDamping = true; \/\/ \u52d5\u304d\u3092\u6ed1\u3089\u304b\u306b\u3059\u308b\n    controls.dampingFactor = 0.05;\n\n    \/\/ === 1-5. \u30e9\u30a4\u30c8 (Lighting) \u306e\u8ffd\u52a0 ===\n    \/\/ \u90e8\u5c4b\u5168\u4f53\u3092\u5747\u7b49\u306b\u7167\u3089\u3059\u74b0\u5883\u5149\n    const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); \/\/ \u5f31\u3081\u306e\u5149\n    scene.add(ambientLight);\n\n    \/\/ \u7279\u5b9a\u306e\u65b9\u5411\u304b\u3089\u7167\u3089\u3059\u6307\u5411\u6027\u5149\uff08\u5f71\u3092\u843d\u3068\u3059\u305f\u3081\u306b\u5fc5\u8981\uff09\n    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);\n    directionalLight.position.set(20, 30, 10);\n    scene.add(directionalLight);\n\n    \/\/ === 1-6 &amp; 1-7. \u90e8\u5c4b\u306e\u69cb\u9020\uff08\u5e8a\u3068\u58c1\uff09\u3068\u30b0\u30ea\u30c3\u30c9\u5b9a\u898f\u306e\u4f5c\u6210 ===\n    createRoomStructure();\n\n    \/\/ === 1-8. \u5bb6\u5177\uff08\u30d7\u30ec\u30fc\u30b9\u30db\u30eb\u30c0\u30fc\uff09\u306e\u4f5c\u6210\u3068\u914d\u7f6e ===\n    \/\/ \u5bb6\u5177\u306e\u914d\u7f6e\u4f8b\n    const deskHeight = 0.75;\n    const chairHeight = 0.5;\n\n    addFurniture(2, 2, 1, 3, 2.0, 0xa0522d); \/\/ \u68da\n    addFurniture(-3, -3, 3, 1.5, deskHeight, 0xdeb887); \/\/ \u30c7\u30b9\u30af\n    \/\/addFurniture(-3, -1, 0.5, 0.5, chairHeight, 0x800000); \/\/ \u30c1\u30a7\u30a2\n    addChair(-3, -1, 0x800000); \/\/ \u30c1\u30a7\u30a2\n    \n    \/\/ \u30a6\u30a3\u30f3\u30c9\u30a6\u30b5\u30a4\u30ba\u304c\u5909\u66f4\u3055\u308c\u305f\u3068\u304d\u306e\u30ea\u30b5\u30a4\u30ba\u51e6\u7406\u3092\u767b\u9332\n    window.addEventListener('resize', onWindowResize, false);\n}\n\n\/\/ 2. \u63cf\u753b\u30eb\u30fc\u30d7\u95a2\u6570\uff1a\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u306e\u5fc3\u81d3\u90e8\nfunction animate() {\n    requestAnimationFrame(animate); \/\/ \u30d6\u30e9\u30a6\u30b6\u306e\u518d\u63cf\u753b\u30bf\u30a4\u30df\u30f3\u30b0\u306b\u5408\u308f\u305b\u3066\u30eb\u30fc\u30d7\u3092\u7d99\u7d9a\n    controls.update(); \/\/ \u30ab\u30e1\u30e9\u64cd\u4f5c\u306e\u30c0\u30f3\u30d4\u30f3\u30b0\u52b9\u679c\u3092\u9069\u7528\u3059\u308b\u305f\u3081\u306b\u66f4\u65b0\u304c\u5fc5\u8981\n    renderer.render(scene, camera); \/\/ \u30b7\u30fc\u30f3\u3092\u30ab\u30e1\u30e9\u306e\u8996\u70b9\u304b\u3089\u63cf\u753b\n}\n\n\/\/ 3. \u30a6\u30a3\u30f3\u30c9\u30a6\u30ea\u30b5\u30a4\u30ba\u51e6\u7406\uff1a\u753b\u9762\u30b5\u30a4\u30ba\u304c\u5909\u308f\u3063\u3066\u3082\u8868\u793a\u3092\u6700\u9069\u5316\nfunction onWindowResize() {\n    camera.aspect = window.innerWidth \/ window.innerHeight;    \/\/ \u30ab\u30e1\u30e9\u306e\u30a2\u30b9\u30da\u30af\u30c8\u6bd4\u66f4\u65b0\n    camera.updateProjectionMatrix(); \/\/ \u30ab\u30e1\u30e9\u306e\u6295\u5f71\u884c\u5217\u3092\u66f4\u65b0\n    renderer.setSize(window.innerWidth, window.innerHeight); \/\/ \u30ec\u30f3\u30c0\u30e9\u30fc\u306e\u30b5\u30a4\u30ba\u66f4\u65b0\n}\n\n\/\/ 4. \u90e8\u5c4b\u5168\u4f53\u69cb\u9020\u306e\u4f5c\u6210\nfunction createRoomStructure() {\n    const wallHeight = 2; \n\n    \/\/ \u5e8a\u306e\u4f5c\u6210\n    const floorGeometry = new THREE.PlaneGeometry(roomSize, roomSize); \n    const floorMaterial = new THREE.MeshStandardMaterial({ \n        color: 0xf8feff,\n        side: THREE.DoubleSide\n    });\n    const floor = new THREE.Mesh(floorGeometry, floorMaterial);\n    floor.rotation.x = Math.PI \/ 2;\n    floor.position.y = 0; \n    floor.receiveShadow = true; \n    roomGroup.add(floor); \n    \n    \/\/ \u8996\u899a\u7684\u5b9a\u898f\uff08GridHelper\uff09\u306e\u8ffd\u52a0 (1m\u9593\u9694)\n    const gridHelper = new THREE.GridHelper(\n        roomSize, roomSize, 0x444444, 0x888888        \n    );\n    gridHelper.position.y = 0.01; \n    roomGroup.add(gridHelper); \n\n    \/\/ \u58c1\u306e\u534a\u900f\u660e\u30de\u30c6\u30ea\u30a2\u30eb\u3092\u4f5c\u6210 \n    const wallMaterial = new THREE.MeshStandardMaterial({ \n        color: 0xf0e68c, \n        transparent: true, \n        opacity: 0.3,      \n        side: THREE.DoubleSide \n    });\n    \n    \/\/ \u58c1\u306e\u4f5c\u6210\u30d8\u30eb\u30d1\u30fc\n    function createWall(x, z, length, height, rotationY) {\n        const wallGeometry = new THREE.BoxGeometry(length, height, 0.1); \n        const wall = new THREE.Mesh(wallGeometry, wallMaterial); \n        \n        wall.position.y = height \/ 2;\n        wall.position.x = x;\n        wall.position.z = z;\n        wall.rotation.y = rotationY;\n        wall.receiveShadow = true;\n        roomGroup.add(wall); \n    }\n    \n    \/\/ 4\u3064\u306e\u58c1\u3092\u4f5c\u6210\n    createWall(0, -roomSize \/ 2, roomSize, wallHeight, 0); \n    createWall(0, roomSize \/ 2, roomSize, wallHeight, 0); \n    createWall(-roomSize \/ 2, 0, roomSize, wallHeight, Math.PI \/ 2); \n    createWall(roomSize \/ 2, 0, roomSize, wallHeight, Math.PI \/ 2); \n}\n\n\/\/ 5.\u5358\u7d14\u306a\u5bb6\u5177\uff08BoxGeometry\uff09\u3092\u8ffd\u52a0\u3059\u308b\nfunction addFurniture(x, z, width, depth, height, color) {\n    \/\/ BoxGeometry: \u7acb\u65b9\u4f53\/\u76f4\u65b9\u4f53\u306e\u5f62\u72b6\n    const geometry = new THREE.BoxGeometry(width, height, depth); \n    const material = new THREE.MeshStandardMaterial({ color: color });\n    const mesh = new THREE.Mesh(geometry, material);\n    \/\/ \u5bb6\u5177\u306eY\u8ef8\u306e\u4f4d\u7f6e\u3092\u5e8a\u304b\u3089\u534a\u5206\u306e\u9ad8\u3055\u306b\u8a2d\u5b9a\n    mesh.position.set(x, height \/ 2, z); \n    mesh.castShadow = true; \n    mesh.receiveShadow = true; \n    \/\/ ID\u3092\u8a2d\u5b9a\u3057\u3001\u4fdd\u5b58\u30fb\u8aad\u307f\u8fbc\u307f\u6642\u306b\u4e00\u8cab\u6027\u3092\u4fdd\u3064\n    mesh.userData.draggable = true;\n    mesh.userData.id = furniture.length; \n    \/\/ \u3053\u306e\u30e1\u30c3\u30b7\u30e5\u304c\u5f8c\u306bRaycaster\u306b\u3088\u308b\u9078\u629e\u306e\u5bfe\u8c61\u3068\u306a\u308b\u3088\u3046\u306b\u8a2d\u5b9a\n    mesh.userData.name = `furniture_${mesh.userData.id}`;\n    \n    roomGroup.add(mesh);  \/\/ roomGroup\u306b\u8ffd\u52a0\n    furniture.push(mesh); \/\/ \u5bb6\u5177\u306e\u4f4d\u7f6e\u72b6\u614b\u3092\u4fdd\u7ba1\n    \n    return mesh;\n}\n\n\/\/ 6.\u8907\u5408\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\uff08\u6905\u5b50\uff09\u3092\u8ffd\u52a0\u3059\u308b\u3001\u8907\u6570\u306eMesh\u3092THREE.Group\u306b\u307e\u3068\u3081\u308b\nfunction addChair(x, z, color) {\n    const CHAIR_W = 0.5;\n    const CHAIR_D = 0.5;\n    const SEAT_H = 0.05;\n    const SEAT_Y = 0.5; \/\/ \u5ea7\u9762\u9ad8\u3055\uff08\u5e8a\u304b\u3089\u306e\u8ddd\u96e2\uff09\n    const LEG_D = 0.05;\n    const BACK_H = 0.4;\n    \n    const chairGroup = new THREE.Group();\n    chairGroup.userData.draggable = true;\n    chairGroup.userData.isComposite = true; \/\/ \u8907\u5408\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30d5\u30e9\u30b0\n    \n    \/\/ \u5168\u3066\u306e\u5b50\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306b\u5171\u901a\u306e\u6750\u8cea\u3092\u9069\u7528\n    const material = new THREE.MeshStandardMaterial({ color: color });\n\n    \/\/ 1. \u5ea7\u9762\n    const seatGeometry = new THREE.BoxGeometry(CHAIR_W, SEAT_H, CHAIR_D);\n    const seat = new THREE.Mesh(seatGeometry, material);\n    \/\/ \u5ea7\u9762\u306e\u4e2d\u5fc3\u304cY=SEAT_Y\u306b\u306a\u308b\u3088\u3046\u306b\u914d\u7f6e\n    seat.position.y = SEAT_Y - SEAT_H \/ 2;\n    seat.castShadow = true; \n    seat.receiveShadow = true;\n    chairGroup.add(seat);\n\n    \/\/ 2. \u80cc\u3082\u305f\u308c\n    const backGeometry = new THREE.BoxGeometry(CHAIR_W, BACK_H, 0.05); \/\/ \u5965\u884c\u304d 5cm\n    const back = new THREE.Mesh(backGeometry, material);\n    \/\/ Y\u4f4d\u7f6e: \u5ea7\u9762\u306e\u4e0a\u9762 (SEAT_Y) + \u80cc\u3082\u305f\u308c\u9ad8\u3055\u306e\u534a\u5206 (BACK_H\/2)\n    \/\/ Z\u4f4d\u7f6e: \u6905\u5b50\u306e\u5965\u884c\u304d\u534a\u5206 (CHAIR_D\/2) - \u80cc\u3082\u305f\u308c\u306e\u5965\u884c\u304d\u534a\u5206 (0.05\/2)\n    back.position.set(0, SEAT_Y + BACK_H \/ 2, CHAIR_D \/ 2 - 0.05 \/ 2);\n    back.castShadow = true; \n    back.receiveShadow = true;\n    chairGroup.add(back);\n\n    \/\/ 3. 4\u672c\u306e\u811a\n    const legH = SEAT_Y - SEAT_H; \/\/ \u811a\u306e\u9ad8\u3055\u306f\u5e8a\u304b\u3089\u5ea7\u9762\u306e\u4e0b\u307e\u3067\n    const legGeometry = new THREE.BoxGeometry(LEG_D, legH, LEG_D);\n    \n    function addLeg(lx, lz) {\n        const leg = new THREE.Mesh(legGeometry, material);\n        \/\/ X\/Z\u4f4d\u7f6e: \u6905\u5b50\u306e\u5e45\/\u5965\u884c\u304d\u304b\u3089\u3001\u811a\u306e\u5965\u884c\u304d\/\u5e45\u306e\u534a\u5206\u3092\u5f15\u3044\u305f\u4f4d\u7f6e\n        \/\/ Y\u4f4d\u7f6e: \u811a\u306e\u9ad8\u3055\u306e\u534a\u5206 (legH\/2)\n        leg.position.set(\n            lx * (CHAIR_W \/ 2 - LEG_D \/ 2), \n            legH \/ 2, \n            lz * (CHAIR_D \/ 2 - LEG_D \/ 2)\n        );\n        leg.castShadow = true; \n        leg.receiveShadow = true;\n        chairGroup.add(leg);\n    }\n    \n    addLeg(1, 1);   \/\/ \u53f3\u5965\n    addLeg(1, -1);  \/\/ \u53f3\u524d\n    addLeg(-1, 1);  \/\/ \u5de6\u5965\n    addLeg(-1, -1); \/\/ \u5de6\u524d\n    \n    \/\/ Group\u81ea\u4f53\u306e\u4f4d\u7f6e\u306f\u3001\u30d4\u30dc\u30c3\u30c8\uff08\u539f\u70b9\uff09\u3092\u5e8a(Y=0)\u306b\u8a2d\u5b9a\n    chairGroup.position.set(x, 0, z); \n    \n    chairGroup.userData.id = furniture.length; \n    chairGroup.userData.name = `chair_${chairGroup.userData.id}`;\n    \n    roomGroup.add(chairGroup);\n    furniture.push(chairGroup); \n    \n    return chairGroup;\n}\n\n\/\/ \u5b9f\u884c\ninit();\nanimate();\n\n<\/code><\/pre>\n\n\n<p><img decoding=\"async\" class=\"wp-image-49232\" style=\"width: 640px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-11.png\" alt=\"VS Code\u5b9f\u884c\u7d50\u679c\u30fc\u30b0\u30eb\u30fc\u30d7\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u8868\u793a\u306e\u78ba\u8a8d\"><\/p>\n\n\n\n<div class=\"wp-block-group has-lightyellow-background-color has-background is-layout-constrained wp-block-group-is-layout-constrained\" style=\"padding-top:10px;padding-right:20px;padding-bottom:10px;padding-left:20px\"><div class=\"wp-block-group__inner-container\">\n<p><img decoding=\"async\" class=\"wp-image-43032\" style=\"width: 32px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/09\/ddns-19.png\" alt=\"\u30ef\u30f3\u30dd\u30a4\u30f3\u30c8\u30d2\u30f3\u30c8\"><strong>Three.js\u3067\u751f\u6210\u3067\u304d\u308b\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u7a2e\u985e<\/strong><\/p>\n\n\n\n<p>\u76f4\u65b9\u4f53\uff08BoxGeometry\uff09\u3001\u5e73\u9762\uff08PlaneGeometry\uff09\u4ee5\u5916\u306b\u3082\u3044\u308d\u3093\u306a\u5f62\u72b6\u306e\u30d7\u30ea\u30df\u30c6\u30a3\u30d6\uff08\u57fa\u672c\u56f3\u5f62\uff09\u304c\u5229\u7528\u3067\u304d\u307e\u3059\u3002<strong>\u30d7\u30ea\u30df\u30c6\u30a3\u30d6\u7acb\u4f53\u3001\u5e73\u9762\u30fb\u30ea\u30f3\u30b0\u3001\u591a\u9762\u4f53\u3001\u30ab\u30b9\u30bf\u30e0\u30fb\u8907\u96d1\u306a\u5f62\u72b6<\/strong>\u306e\u95a2\u6570\u304c\u7528\u610f\u3055\u308c\u3066\u304a\u308a\u3001\u305d\u308c\u3089\u3092\u7d44\u307f\u5408\u308f\u305b\u308b\u3053\u3068\u3067\u591a\u69d8\u306a\u69cb\u9020\u7269\u3092\u4f5c\u6210\u3067\u304d\u307e\u3059\u3002\u3053\u308c\u3089\u306e\u30af\u30e9\u30b9\u306f\u30013D\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u5f62\u72b6\u30c7\u30fc\u30bf\uff08\u9802\u70b9\u3001\u9762\u3001\u30a8\u30c3\u30b8\uff09\u3092\u5b9a\u7fa9\u3057\u3001\u30e1\u30c3\u30b7\u30e5\uff08THREE.Mesh\uff09 \u306e\u4f5c\u6210\u306b\u4f7f\u7528\u3055\u308c\u307e\u3059\u3002<br>\u672c\u8a18\u4e8b\u3067\u306f\u4e0b\u8868\u306e<strong>BoxGeometry<\/strong>\u3001<strong>SphereGeometry<\/strong>\u3001<strong>PlaneGeometry<\/strong>\u3001<strong>RingGeometry<\/strong>\u3001<strong>BufferGeometry<\/strong>\u3092\u4f7f\u3063\u3066\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<figure class=\"wp-block-table\">\n<table style=\"height: 1168px\" cellspacing=\"0\" cellpadding=\"0\">\n<thead>\n<tr style=\"height: 48px\">\n<th style=\"height: 48px;width: 104.312px\">\u5206\u985e<\/th>\n<th style=\"height: 48px;width: 185.55px\">\u30af\u30e9\u30b9\u540d<\/th>\n<th style=\"height: 48px;width: 161.475px\">\u5f62\u72b6<\/th>\n<th style=\"height: 48px;width: 279.862px\">\u6982\u8981<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr style=\"height: 75px\">\n<td style=\"height: 327px;width: 104.312px\" rowspan=\"4\">\u30d7\u30ea\u30df\u30c6\u30a3\u30d6\u7acb\u4f53<\/td>\n<td style=\"height: 75px;width: 185.55px\"><strong>BoxGeometry<\/strong><\/td>\n<td style=\"height: 75px;width: 161.475px\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-49638\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-17.png\" alt=\"BoxGeometry\" width=\"42\" height=\"36\" \/><strong>\u76f4\u65b9\/\u7acb\u65b9\u4f53<\/strong><\/td>\n<td style=\"height: 75px;width: 279.862px\">\u5e45\u3001\u9ad8\u3055\u3001\u5965\u884c\u304d\u3092\u6307\u5b9a\u3057\u3066\u4f5c\u6210\u3059\u308b\u57fa\u672c\u306e\u7bb1\u578b\u7acb\u4f53\u3067\u3059\u3002<\/td>\n<\/tr>\n<tr style=\"height: 77px\">\n<td style=\"height: 86px;width: 185.55px\"><strong>SphereGeometry<\/strong><\/td>\n<td style=\"height: 86px;width: 161.475px\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-49639\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-18.png\" alt=\"SphereGeometry\" width=\"42\" height=\"36\" \/><strong>\u7403\u4f53<\/strong><\/td>\n<td style=\"height: 86px;width: 279.862px\">\u534a\u5f84\u3068\u5206\u5272\u6570\u3092\u6307\u5b9a\u3057\u3066\u5b8c\u5168\u306a\u7403\u4f53\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/td>\n<\/tr>\n<tr style=\"height: 83px\">\n<td style=\"height: 83px;width: 185.55px\">CylinderGeometry<\/td>\n<td style=\"height: 83px;width: 161.475px\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-49640\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-19.png\" alt=\"CylinderGeometry\" width=\"42\" height=\"36\" \/>\u5186\u67f1\/\u5186\u9310<\/td>\n<td style=\"height: 83px;width: 279.862px\">\u4e0a\u4e0b\u4e21\u9762\u306e\u534a\u5f84\u3001\u9ad8\u3055\u3001\u5206\u5272\u6570\u3092\u6307\u5b9a\u3057\u3066\u5186\u67f1\u3084\u5186\u9310\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/td>\n<\/tr>\n<tr style=\"height: 83px\">\n<td style=\"height: 83px;width: 185.55px\">TorusGeometry<\/td>\n<td style=\"height: 83px;width: 161.475px\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-49641\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-20.png\" alt=\"TorusGeometry\" width=\"42\" height=\"36\" \/>\u30c8\u30fc\u30e9\u30b9<\/td>\n<td style=\"height: 83px;width: 279.862px\">\u30c9\u30fc\u30ca\u30c4\u578b\uff08\u6d6e\u304d\u8f2a\u578b\uff09\u306e3D\u5f62\u72b6\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/td>\n<\/tr>\n<tr style=\"height: 77px\">\n<td style=\"height: 231px;width: 104.312px\" rowspan=\"3\">\u5e73\u9762\u30fb\u30ea\u30f3\u30b0<\/td>\n<td style=\"height: 77px;width: 185.55px\"><strong>PlaneGeometry<\/strong><\/td>\n<td style=\"height: 77px;width: 161.475px\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-49642\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-21.png\" alt=\"PlaneGeometry\" width=\"42\" height=\"36\" \/><strong>\u5e73\u9762<\/strong><\/td>\n<td style=\"height: 77px;width: 279.862px\">\u5e45\u3068\u9ad8\u3055\u3092\u6307\u5b9a\u3057\u3066\u5e73\u3089\u306a\u9577\u65b9\u5f62\u306e\u9762\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/td>\n<\/tr>\n<tr style=\"height: 77px\">\n<td style=\"height: 77px;width: 185.55px\">CircleGeometry<\/td>\n<td style=\"height: 77px;width: 161.475px\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-49643\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-22.png\" alt=\"CircleGeometry\" width=\"42\" height=\"36\" \/>\u5186\/\u6247\u5f62<\/td>\n<td style=\"height: 77px;width: 279.862px\">\u534a\u5f84\u3068\u5206\u5272\u6570\u3092\u6307\u5b9a\u3057\u3066\u5e73\u3089\u306a\u5186\u307e\u305f\u306f\u6247\u5f62\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/td>\n<\/tr>\n<tr style=\"height: 77px\">\n<td style=\"height: 77px;width: 185.55px\"><strong>RingGeometry<\/strong><\/td>\n<td style=\"height: 77px;width: 161.475px\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-49644\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-23.png\" alt=\"RingGeometry\" width=\"42\" height=\"36\" \/><strong>\u30ea\u30f3\u30b0<\/strong><\/td>\n<td style=\"height: 77px;width: 279.862px\">\u5185\u5f84\u3068\u5916\u5f84\u3092\u6307\u5b9a\u3057\u3066\u30c9\u30fc\u30ca\u30c4\u578b\u306e\u5e73\u3089\u306a\u30ea\u30f3\u30b0\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/td>\n<\/tr>\n<tr style=\"height: 82px\">\n<td style=\"height: 248px;width: 104.312px\" rowspan=\"3\">\u591a\u9762\u4f53<\/td>\n<td style=\"height: 82px;width: 185.55px\">TetrahedronGeometry<\/td>\n<td style=\"height: 82px;width: 161.475px\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-49645\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-24.png\" alt=\"TetrahedronGeometry\" width=\"41\" height=\"35\" \/>\u6b63\u56db\u9762\u4f53<\/td>\n<td style=\"height: 82px;width: 279.862px\">4\u3064\u306e\u9762\u3092\u6301\u3064\u7acb\u4f53\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/td>\n<\/tr>\n<tr style=\"height: 83px\">\n<td style=\"height: 83px;width: 185.55px\">OctahedronGeometry<\/td>\n<td style=\"height: 83px;width: 161.475px\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-49646\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-25.png\" alt=\"OctahedronGeometry\" width=\"42\" height=\"36\" \/>\u6b63\u516b\u9762\u4f53<\/td>\n<td style=\"height: 83px;width: 279.862px\">8\u3064\u306e\u9762\u3092\u6301\u3064\u7acb\u4f53\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/td>\n<\/tr>\n<tr style=\"height: 83px\">\n<td style=\"height: 83px;width: 185.55px\">IcosahedronGeometry<\/td>\n<td style=\"height: 83px;width: 161.475px\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-49647\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-26.png\" alt=\"IcosahedronGeometry\" width=\"42\" height=\"36\" \/>\u6b63\u4e8c\u5341\u9762\u4f53<\/td>\n<td style=\"height: 83px;width: 279.862px\">20\u306e\u9762\u3092\u6301\u3064\u7acb\u4f53\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/td>\n<\/tr>\n<tr style=\"height: 83px\">\n<td style=\"height: 314px;width: 104.312px\" rowspan=\"4\">\u30ab\u30b9\u30bf\u30e0\u30fb\u8907\u96d1\u306a\u5f62\u72b6<\/td>\n<td style=\"height: 83px;width: 185.55px\">ExtrudeGeometry<\/td>\n<td style=\"height: 83px;width: 161.475px\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-49648\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-27.png\" alt=\"ExtrudeGeometry\" width=\"42\" height=\"36\" \/>\u62bc\u51fa\u5f62\u72b6<\/td>\n<td style=\"height: 83px;width: 279.862px\">2D\u306e\u5f62\u72b6\u30923\u6b21\u5143\u65b9\u5411\u306b\u62bc\u3057\u51fa\u3057\u3066\u7acb\u4f53\u3092\u4f5c\u6210\u3057\u307e\u3059\uff08\u4f8b\uff1a3D\u30ed\u30b4\uff09\u3002<\/td>\n<\/tr>\n<tr style=\"height: 77px\">\n<td style=\"height: 77px;width: 185.55px\">LatheGeometry<\/td>\n<td style=\"height: 77px;width: 161.475px\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-49649\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-28.png\" alt=\"LatheGeometry\" width=\"42\" height=\"36\" \/>\u56de\u8ee2\u4f53<\/td>\n<td style=\"height: 77px;width: 279.862px\">2D\u306e\u30d7\u30ed\u30d5\u30a1\u30a4\u30eb\u3092\u8ef8\u3092\u4e2d\u5fc3\u306b\u56de\u8ee2\u3055\u305b\u3066\u4f5c\u6210\u3059\u308b\u5f62\u72b6\uff08\u4f8b\uff1a\u82b1\u74f6\uff09\u3002<\/td>\n<\/tr>\n<tr style=\"height: 77px\">\n<td style=\"height: 77px;width: 185.55px\">TextGeometry<\/td>\n<td style=\"height: 77px;width: 161.475px\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-49650\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-29.png\" alt=\"TextGeometry\" width=\"42\" height=\"36\" \/>3D\u30c6\u30ad\u30b9\u30c8<\/td>\n<td style=\"height: 77px;width: 279.862px\">\u6307\u5b9a\u3057\u305f\u30d5\u30a9\u30f3\u30c8\u3068\u6587\u5b57\u5217\u304b\u30893D\u306e\u6587\u5b57\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/td>\n<\/tr>\n<tr style=\"height: 77px\">\n<td style=\"height: 77px;width: 185.55px\"><strong>BufferGeometry<\/strong><\/td>\n<td style=\"height: 77px;width: 161.475px\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-49651\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-30.png\" alt=\"BufferGeometry\" width=\"42\" height=\"36\" \/><strong>\u30ab\u30b9\u30bf\u30e0<\/strong><\/td>\n<td style=\"height: 77px;width: 279.862px\">\u9802\u70b9\u5ea7\u6a19\u306a\u3069\u3092\u914d\u5217\u3068\u3057\u3066\u624b\u52d5\u3067\u5b9a\u7fa9\u3059\u308b\u305f\u3081\u306e\u3001\u6700\u3082\u67d4\u8edf\u306a\u57fa\u672c\u30af\u30e9\u30b9\u3067\u3059\u3002<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<\/div><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">3D\u30e2\u30c7\u30eb\u306e\u30b9\u30ab\u30eb\u30d7\u30c8\u30c7\u30fc\u30bf\u3092\u30ed\u30fc\u30c9\u3057\u3066\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u8a2d\u7f6e\u3059\u308b<\/h3>\n\n\n\n<p><strong>Blender<\/strong>\u3084<strong>ZBrush<\/strong>\u306a\u3069\u3067\u4f5c\u6210\u3057\u305f\u300c\u30b9\u30ab\u30eb\u30d7\u30c8\uff08\u5f6b\u523b\uff09\u300d\u3001\u3042\u308b\u3044\u306f<strong>\u751f\u6210AI<\/strong>\u3067\u4f5c\u6210\u3057\u305f3D\u30e2\u30c7\u30eb\u30c7\u30fc\u30bf\u3092\u300c.glb\u300d\u30d5\u30a1\u30a4\u30eb\u306b\u30a8\u30af\u30b9\u30dd\u30fc\u30c8\u3057\u305d\u308c\u3092\u5229\u7528\u3059\u308b\u3053\u3068\u3082\u3067\u304d\u307e\u3059\u3002<br>\u3053\u308c\u306b\u3088\u3063\u3066\u8907\u96d1\u306a\u5f62\u72b6\u3092\u6301\u3064\u5bb6\u5177\u3001\u88c5\u98fe\u54c1\u3001\u5f6b\u523b\u306a\u3069\u306e\u30e2\u30c7\u30eb\u3092\u30b7\u30fc\u30f3\u306b\u8aad\u307f\u8fbc\u3080\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u4eca\u56de\u4f7f\u7528\u3059\u308b\u9f8d\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306f<strong><a href=\"https:\/\/studio.tripo3d.ai\/\" target=\"_blank\" rel=\"noreferrer noopener\">Tripo 3D<\/a><\/strong>\u306e\u751f\u6210AI\u3067\u4f5c\u6210\u3057\u307e\u3057\u305f\u3002<br>\u203bTripo 3D\u306e\u62db\u5f85\u30b3\u30fc\u30c9\uff1aBG8U9G\u3092\u5229\u7528\u3059\u308c\u3070\uff13\uff10\uff10\u30af\u30ec\u30b8\u30c3\u30c8\u304c\u7121\u6599\u3067\u63d0\u4f9b\u3055\u308c\u307e\u3059\u306e\u3067\u8208\u5473\u3042\u308b\u65b9\u306f\u3054\u5229\u7528\u304f\u3060\u3055\u3044\u3002\u53c2\u8003\u3068\u3057\u3066\u9f8d\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306f\uff13\uff15\u30af\u30ec\u30b8\u30c3\u30c8\u306e\u6d88\u8cbb\u3067\u4f5c\u6210\u3067\u304d\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<p><img decoding=\"async\" class=\"wp-image-49257\" style=\"width: 420px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-14.png\" alt=\"3D\u9f8d\"><\/p>\n\n\n\n<p>\u9f8d\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306f<a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/picolix\/sculpdata\/archive\/refs\/heads\/main.zip\" target=\"_blank\">https:\/\/github.com\/picolix\/sculpdata\/archive\/refs\/heads\/main.zip<\/a>\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3067\u304d\u307e\u3059\u3002\u89e3\u51cd\u3059\u308b\u3068<strong>dragon-3d-model-2.glb<\/strong>\u304c\u3067\u304d\u307e\u3059\u306e\u3067\u30d5\u30a9\u30eb\u30c0\u306e\u30c8\u30c3\u30d7\u968e\u5c64\u306b\u30b3\u30d4\u30fc\u3057\u3066\u304f\u3060\u3055\u3044\u3002<br><br>\u3053\u306e<strong>glb\u30d5\u30a1\u30a4\u30eb<\/strong>\u3092GLTFLoader()\u3067\u30ed\u30fc\u30c9\u3057\u3066\u90e8\u5c4b\u306b\u8a2d\u7f6e\u3057\u307e\u3059\u3002\u3053\u308c\u306b\u3088\u3063\u3066\u8907\u96d1\u306a\u5f62\u72b6\u3092\u6301\u3064\u5bb6\u5177\u3001\u88c5\u98fe\u54c1\u3001\u5f6b\u523b\u306a\u3069\u306e\u30e2\u30c7\u30eb\u3092\u30b7\u30fc\u30f3\u306b\u8aad\u307f\u8fbc\u3080\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<div class=\"wp-block-luxe-blocks-topic\" style=\"margin-top:10px;margin-bottom:30px\"><div class=\"wp-block-luxe-blocks-topic-title\" style=\"color:#fff;background-color:#006edc;border:1px solid #006edc;padding:2px 14px;align-items:center\">main.js \u8ffd\u52a0\u5185\u5bb9<\/div><div class=\"wp-block-luxe-blocks-topic-content\" style=\"border:1px solid #006edc;padding:0px 15px 0px 15px\">\n\n<ul type=\"1\">\n\n<li>\/\/ === 1-8. \u5bb6\u5177\uff08\u30d7\u30ec\u30fc\u30b9\u30db\u30eb\u30c0\u30fc\uff09\u306e\u4f5c\u6210\u3068\u914d\u7f6e ===<br>addLoadSculptedModel('.\/dragon-3d-model-2.glb',-3, 1.3,-2.8,Math.PI \/ 2,2.0);\u3092\u8ffd\u52a0\u3057\u307e\u3057\u305f\u3002<br>\u5f15\u6570\uff1aX,Y,Z\uff1d(-3,1.3,-2.8)\u306e\u673a\u306e\u4e0a\u306b\u914d\u7f6e\u3057\u307e\u3059\u3002Math.PI \/ 2\u306f\uff19\uff10\u5ea6\u56de\u8ee2\u3055\u305b\u308b\u30022.0\u306f\uff12\u500d\u306e\u30b5\u30a4\u30ba\u306b\u3057\u307e\u3059\u3002<\/li>\n\n\n<li>addLoadSculptedModel()\u95a2\u6570\u306e\u8ffd\u52a0<br>GLB\u30d5\u30a1\u30a4\u30eb\u3092\u975e\u540c\u671f\u3067\u30ed\u30fc\u30c9\u3057roomGroup\u306b\u8ffd\u52a0\u3057\u307e\u3059\u3002<\/li>\n\n<\/ul>\n\n<\/div><\/div>\n\n\n<pre class=\"line-numbers highlight-code-sculp\"><code class=\"language-javascript\">\/\/ main.js\n\/\/ [main-004-sclup]\n\/\/ index.html \u306e importmap \u306e\u8a2d\u5b9a\u306b\u57fa\u3065\u304d\u3001\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\u3092\u30a4\u30f3\u30dd\u30fc\u30c8\nimport * as THREE from \"three\";\nimport { OrbitControls } from '.\/jsm\/controls\/OrbitControls.js';\nimport { GLTFLoader } from '.\/jsm\/loaders\/GLTFLoader.js';\n\/\/ \u5fc5\u8981\u306a\u5909\u6570\u3092\u30b0\u30ed\u30fc\u30d0\u30eb\u30b9\u30b3\u30fc\u30d7\u3067\u5b9a\u7fa9\nlet scene, camera, renderer, controls;\nlet roomGroup; \/\/ \u5e8a\u3001\u58c1\u3001\u5bb6\u5177\u3092\u307e\u3068\u3081\u308b\u30b0\u30eb\u30fc\u30d7\nlet gltfLoader; \/\/ GLTF\u30ed\u30fc\u30c0\u30fc\nconst roomSize = 10; \/\/ \u90e8\u5c4b\u306e\u30b5\u30a4\u30ba (10m x 10m)\nconst furniture = []; \/\/ \u8907\u6570\u306e\u5bb6\u5177\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u9806\u5e8f\u4ed8\u3051\u3057\u3066\u4fdd\u7ba1\n\/\/ 1. \u521d\u671f\u5316\u95a2\u6570\uff1a3D\u4e16\u754c\u306e\u571f\u53f0\u3092\u4f5c\u308b\nfunction init() {\n    \/\/ === 1-1. \u30b7\u30fc\u30f3 (Scene) \u306e\u4f5c\u6210 ===\n    scene = new THREE.Scene();\n    scene.background = new THREE.Color(0xf0f0f0); \/\/ \u80cc\u666f\u8272\u3092\u8584\u3044\u30b0\u30ec\u30fc\u306b\u8a2d\u5b9a\n    roomGroup = new THREE.Group();\n    scene.add(roomGroup);\n    \/\/ \u5ea7\u6a19\u8ef8\u30d8\u30eb\u30d1\u30fc\u3092\u8ffd\u52a0\uff08X\u8ef8\uff1a\u8d64\u3001Y\u8ef8\uff1a\u7dd1\u3001Z\u8ef8\uff1a\u9752\uff09\n    const axesHelper = new THREE.AxesHelper(10); \/\/ \u30b5\u30a4\u30ba10\n    scene.add(axesHelper);\n\n    \/\/ === 1-2. \u30ab\u30e1\u30e9 (Camera) \u306e\u8a2d\u5b9a ===\n    const fov = 75; \/\/ \u8996\u91ce\u89d2 (Field of View)\n    const aspect = window.innerWidth \/ window.innerHeight; \/\/ \u30a2\u30b9\u30da\u30af\u30c8\u6bd4\n    const near = 0.1; \/\/ \u63cf\u753b\u958b\u59cb\u8ddd\u96e2\n    const far = 1000; \/\/ \u63cf\u753b\u7d42\u4e86\u8ddd\u96e2\n    camera = new THREE.PerspectiveCamera(fov, aspect, near, far);\n    \/\/ \u30ab\u30e1\u30e9\u306e\u521d\u671f\u4f4d\u7f6e\u3092\u6c7a\u5b9a (X, Y, Z)\n    camera.position.set(10, 15, 15);\n    camera.lookAt(0, 0, 0); \/\/ \u539f\u70b9(0, 0, 0)\u3092\u898b\u308b\u3088\u3046\u306b\u8a2d\u5b9a\n\n    \/\/ === 1-3. \u30ec\u30f3\u30c0\u30e9\u30fc (Renderer) \u306e\u4f5c\u6210 ===\n    renderer = new THREE.WebGLRenderer({ antialias: true }); \/\/ \u30a2\u30f3\u30c1\u30a8\u30a4\u30ea\u30a2\u30b9\u3067\u63cf\u753b\u3092\u6ed1\u3089\u304b\u306b\n    renderer.setSize(window.innerWidth, window.innerHeight); \/\/ \u63cf\u753b\u30b5\u30a4\u30ba\u3092\u30a6\u30a3\u30f3\u30c9\u30a6\u30b5\u30a4\u30ba\u306b\u5408\u308f\u305b\u308b\n    renderer.outputEncoding = THREE.sRGBEncoding; \/\/ \u30ec\u30f3\u30c0\u30ea\u30f3\u30b0\u54c1\u8cea\u6539\u5584\n    renderer.shadowMap.enabled = true; \/\/ \u5f71\u306e\u63cf\u753b\u3092\u6709\u52b9\u5316\n\n    \/\/ GLTF\u30ed\u30fc\u30c0\u30fc\u306e\u521d\u671f\u5316\n    gltfLoader = new GLTFLoader(); \n\n    \/\/ \u751f\u6210\u3055\u308c\u305f&lt;canvas&gt;\u8981\u7d20\u3092HTML&lt;body&gt;\u306b\u8ffd\u52a0\n    document.body.appendChild(renderer.domElement);\n\n    \/\/ === 1-4. \u30ab\u30e1\u30e9\u64cd\u4f5c (OrbitControls) \u306e\u8a2d\u5b9a ===\n    \/\/ \u30a4\u30f3\u30dd\u30fc\u30c8\u3057\u305f OrbitControls \u3092\u4f7f\u3063\u3066\u3001\u30de\u30a6\u30b9\u3067\u30ab\u30e1\u30e9\u3092\u52d5\u304b\u305b\u308b\u3088\u3046\u306b\u3059\u308b\n    controls = new OrbitControls(camera, renderer.domElement);\n    controls.enableDamping = true; \/\/ \u52d5\u304d\u3092\u6ed1\u3089\u304b\u306b\u3059\u308b\n    controls.dampingFactor = 0.05;\n\n    \/\/ === 1-5. \u30e9\u30a4\u30c8 (Lighting) \u306e\u8ffd\u52a0 ===\n    \/\/ \u90e8\u5c4b\u5168\u4f53\u3092\u5747\u7b49\u306b\u7167\u3089\u3059\u74b0\u5883\u5149\n    const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); \/\/ \u5f31\u3081\u306e\u5149\n    scene.add(ambientLight);\n    \/\/ \u7279\u5b9a\u306e\u65b9\u5411\u304b\u3089\u7167\u3089\u3059\u6307\u5411\u6027\u5149\uff08\u5f71\u3092\u843d\u3068\u3059\u305f\u3081\u306b\u5fc5\u8981\uff09\n    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);\n    directionalLight.position.set(20, 30, 10);\n    scene.add(directionalLight);\n\n    \/\/ === 1-6 &amp; 1-7. \u90e8\u5c4b\u306e\u69cb\u9020\uff08\u5e8a\u3068\u58c1\uff09\u3068\u30b0\u30ea\u30c3\u30c9\u5b9a\u898f\u306e\u4f5c\u6210 ===\n    createRoomStructure();\n\n    \/\/ === 1-8. \u5bb6\u5177\uff08\u30d7\u30ec\u30fc\u30b9\u30db\u30eb\u30c0\u30fc\uff09\u306e\u4f5c\u6210\u3068\u914d\u7f6e ===\n    \/\/ \u5bb6\u5177\u306e\u914d\u7f6e\u4f8b\n    const deskHeight = 0.75;\n    const chairHeight = 0.5;\n    addFurniture(2, 2, 1, 3, 2.0, 0xa0522d); \/\/ \u68da\n    addFurniture(-3, -3, 3, 1.5, deskHeight, 0xdeb887); \/\/ \u30c7\u30b9\u30af\n    \/\/addFurniture(-3, -1, 0.5, 0.5, chairHeight, 0x800000); \/\/ \u30c1\u30a7\u30a2\n    addChair(-3, -1, 0x800000); \/\/ \u30c1\u30a7\u30a2\n    \n    \/\/ \u30b9\u30ab\u30eb\u30d7\u30c8\u30e2\u30c7\u30eb(\u9f8d)\u306e\u30ed\u30fc\u30c9\u3068\u914d\u7f6e\n    addLoadSculptedModel('.\/dragon-3d-model-2.glb',-3, 1.3,-2.8,Math.PI \/ 2,2.0);\n\n    \/\/ \u30a6\u30a3\u30f3\u30c9\u30a6\u30b5\u30a4\u30ba\u304c\u5909\u66f4\u3055\u308c\u305f\u3068\u304d\u306e\u30ea\u30b5\u30a4\u30ba\u51e6\u7406\u3092\u767b\u9332\n    window.addEventListener('resize', onWindowResize, false);\n}\n\/\/ 2. \u63cf\u753b\u30eb\u30fc\u30d7\u95a2\u6570\uff1a\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u306e\u5fc3\u81d3\u90e8\nfunction animate() {\n    requestAnimationFrame(animate); \/\/ \u30d6\u30e9\u30a6\u30b6\u306e\u518d\u63cf\u753b\u30bf\u30a4\u30df\u30f3\u30b0\u306b\u5408\u308f\u305b\u3066\u30eb\u30fc\u30d7\u3092\u7d99\u7d9a\n    controls.update(); \/\/ \u30ab\u30e1\u30e9\u64cd\u4f5c\u306e\u30c0\u30f3\u30d4\u30f3\u30b0\u52b9\u679c\u3092\u9069\u7528\u3059\u308b\u305f\u3081\u306b\u66f4\u65b0\u304c\u5fc5\u8981\n    renderer.render(scene, camera); \/\/ \u30b7\u30fc\u30f3\u3092\u30ab\u30e1\u30e9\u306e\u8996\u70b9\u304b\u3089\u63cf\u753b\n}\n\/\/ 3. \u30a6\u30a3\u30f3\u30c9\u30a6\u30ea\u30b5\u30a4\u30ba\u51e6\u7406\uff1a\u753b\u9762\u30b5\u30a4\u30ba\u304c\u5909\u308f\u3063\u3066\u3082\u8868\u793a\u3092\u6700\u9069\u5316\nfunction onWindowResize() {\n    camera.aspect = window.innerWidth \/ window.innerHeight;    \/\/ \u30ab\u30e1\u30e9\u306e\u30a2\u30b9\u30da\u30af\u30c8\u6bd4\u66f4\u65b0\n    camera.updateProjectionMatrix(); \/\/ \u30ab\u30e1\u30e9\u306e\u6295\u5f71\u884c\u5217\u3092\u66f4\u65b0\n    renderer.setSize(window.innerWidth, window.innerHeight); \/\/ \u30ec\u30f3\u30c0\u30e9\u30fc\u306e\u30b5\u30a4\u30ba\u66f4\u65b0\n}\n\/\/ 4. \u90e8\u5c4b\u5168\u4f53\u69cb\u9020\u306e\u4f5c\u6210\nfunction createRoomStructure() {\n    const wallHeight = 2; \n    \/\/ \u5e8a\u306e\u4f5c\u6210\n    const floorGeometry = new THREE.PlaneGeometry(roomSize, roomSize); \n    const floorMaterial = new THREE.MeshStandardMaterial({ \n        color: 0xf8feff,\n        side: THREE.DoubleSide\n    });\n    const floor = new THREE.Mesh(floorGeometry, floorMaterial);\n    floor.rotation.x = Math.PI \/ 2;\n    floor.position.y = 0; \n    floor.receiveShadow = true; \n    roomGroup.add(floor); \n    \n    \/\/ \u8996\u899a\u7684\u5b9a\u898f\uff08GridHelper\uff09\u306e\u8ffd\u52a0 (1m\u9593\u9694)\n    const gridHelper = new THREE.GridHelper(\n        roomSize, roomSize, 0x444444, 0x888888        \n    );\n    gridHelper.position.y = 0.01; \n    roomGroup.add(gridHelper); \n    \/\/ \u58c1\u306e\u534a\u900f\u660e\u30de\u30c6\u30ea\u30a2\u30eb\u3092\u4f5c\u6210 \n    const wallMaterial = new THREE.MeshStandardMaterial({ \n        color: 0xf0e68c,\n        transparent: true, \n        opacity: 0.3,      \n        side: THREE.DoubleSide \n    });\n    \n    \/\/ \u58c1\u306e\u4f5c\u6210\u30d8\u30eb\u30d1\u30fc\n    function createWall(x, z, length, height, rotationY) {\n        const wallGeometry = new THREE.BoxGeometry(length, height, 0.1); \n        const wall = new THREE.Mesh(wallGeometry, wallMaterial); \n        \n        wall.position.y = height \/ 2;\n        wall.position.x = x;\n        wall.position.z = z;\n        wall.rotation.y = rotationY;\n        wall.receiveShadow = true;\n        roomGroup.add(wall); \n    }\n    \n    \/\/ 4\u3064\u306e\u58c1\u3092\u4f5c\u6210\n    createWall(0, -roomSize \/ 2, roomSize, wallHeight, 0); \n    createWall(0, roomSize \/ 2, roomSize, wallHeight, 0); \n    createWall(-roomSize \/ 2, 0, roomSize, wallHeight, Math.PI \/ 2); \n    createWall(roomSize \/ 2, 0, roomSize, wallHeight, Math.PI \/ 2); \n}\n\/\/ 5.\u5358\u7d14\u306a\u5bb6\u5177\uff08BoxGeometry\uff09\u3092\u8ffd\u52a0\u3059\u308b\nfunction addFurniture(x, z, width, depth, height, color) {\n    \/\/ BoxGeometry: \u7acb\u65b9\u4f53\/\u76f4\u65b9\u4f53\u306e\u5f62\u72b6\n    const geometry = new THREE.BoxGeometry(width, height, depth); \n    const material = new THREE.MeshStandardMaterial({ color: color });\n    const mesh = new THREE.Mesh(geometry, material);\n    \/\/ \u5bb6\u5177\u306eY\u8ef8\u306e\u4f4d\u7f6e\u3092\u5e8a\u304b\u3089\u534a\u5206\u306e\u9ad8\u3055\u306b\u8a2d\u5b9a\n    mesh.position.set(x, height \/ 2, z); \n    mesh.castShadow = true; \n    mesh.receiveShadow = true;\n    \/\/ ID\u3092\u8a2d\u5b9a\u3057\u3001\u4fdd\u5b58\u30fb\u8aad\u307f\u8fbc\u307f\u6642\u306b\u4e00\u8cab\u6027\u3092\u4fdd\u3064\n    mesh.userData.draggable = true;\n    mesh.userData.id = furniture.length; \n    \/\/ \u3053\u306e\u30e1\u30c3\u30b7\u30e5\u304c\u5f8c\u306bRaycaster\u306b\u3088\u308b\u9078\u629e\u306e\u5bfe\u8c61\u3068\u306a\u308b\u3088\u3046\u306b\u8a2d\u5b9a\n    mesh.userData.name = `furniture_${mesh.userData.id}`;\n    \n    roomGroup.add(mesh);  \/\/ roomGroup\u306b\u8ffd\u52a0\n    furniture.push(mesh); \/\/ \u5bb6\u5177\u306e\u4f4d\u7f6e\u72b6\u614b\u3092\u4fdd\u7ba1\n    \n    return mesh;\n}\n\/\/ 6.\u8907\u5408\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\uff08\u6905\u5b50\uff09\u3092\u8ffd\u52a0\u3059\u308b\u3001\u8907\u6570\u306eMesh\u3092THREE.Group\u306b\u307e\u3068\u3081\u308b\nfunction addChair(x, z, color) {\n    const CHAIR_W = 0.5;\n    const CHAIR_D = 0.5;\n    const SEAT_H = 0.05;\n    const SEAT_Y = 0.5; \/\/ \u5ea7\u9762\u9ad8\u3055\uff08\u5e8a\u304b\u3089\u306e\u8ddd\u96e2\uff09\n    const LEG_D = 0.05;\n    const BACK_H = 0.4;\n    \n    const chairGroup = new THREE.Group();\n    chairGroup.userData.draggable = true;\n    chairGroup.userData.isComposite = true; \/\/ \u8907\u5408\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30d5\u30e9\u30b0\n    \n    \/\/ \u5168\u3066\u306e\u5b50\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306b\u5171\u901a\u306e\u6750\u8cea\u3092\u9069\u7528\n    const material = new THREE.MeshStandardMaterial({ color: color });\n    \/\/ 1. \u5ea7\u9762\n    const seatGeometry = new THREE.BoxGeometry(CHAIR_W, SEAT_H, CHAIR_D);\n    const seat = new THREE.Mesh(seatGeometry, material);\n    \/\/ \u5ea7\u9762\u306e\u4e2d\u5fc3\u304cY=SEAT_Y\u306b\u306a\u308b\u3088\u3046\u306b\u914d\u7f6e\n    seat.position.y = SEAT_Y - SEAT_H \/ 2;\n    seat.castShadow = true; \n    seat.receiveShadow = true;\n    chairGroup.add(seat);\n    \/\/ 2. \u80cc\u3082\u305f\u308c\n    const backGeometry = new THREE.BoxGeometry(CHAIR_W, BACK_H, 0.05); \/\/ \u5965\u884c\u304d 5cm\n    const back = new THREE.Mesh(backGeometry, material);\n    \/\/ Y\u4f4d\u7f6e: \u5ea7\u9762\u306e\u4e0a\u9762 (SEAT_Y) + \u80cc\u3082\u305f\u308c\u9ad8\u3055\u306e\u534a\u5206 (BACK_H\/2)\n    \/\/ Z\u4f4d\u7f6e: \u6905\u5b50\u306e\u5965\u884c\u304d\u534a\u5206 (CHAIR_D\/2) - \u80cc\u3082\u305f\u308c\u306e\u5965\u884c\u304d\u534a\u5206 (0.05\/2)\n    back.position.set(0, SEAT_Y + BACK_H \/ 2, CHAIR_D \/ 2 - 0.05 \/ 2);\n    back.castShadow = true; \n    back.receiveShadow = true;\n    chairGroup.add(back);\n    \/\/ 3. 4\u672c\u306e\u811a\n    const legH = SEAT_Y - SEAT_H; \/\/ \u811a\u306e\u9ad8\u3055\u306f\u5e8a\u304b\u3089\u5ea7\u9762\u306e\u4e0b\u307e\u3067\n    const legGeometry = new THREE.BoxGeometry(LEG_D, legH, LEG_D);\n    \n    function addLeg(lx, lz) {\n        const leg = new THREE.Mesh(legGeometry, material);\n        \/\/ X\/Z\u4f4d\u7f6e: \u6905\u5b50\u306e\u5e45\/\u5965\u884c\u304d\u304b\u3089\u3001\u811a\u306e\u5965\u884c\u304d\/\u5e45\u306e\u534a\u5206\u3092\u5f15\u3044\u305f\u4f4d\u7f6e\n        \/\/ Y\u4f4d\u7f6e: \u811a\u306e\u9ad8\u3055\u306e\u534a\u5206 (legH\/2)\n        leg.position.set(\n            lx * (CHAIR_W \/ 2 - LEG_D \/ 2), \n            legH \/ 2, \n            lz * (CHAIR_D \/ 2 - LEG_D \/ 2)\n        );\n        leg.castShadow = true;\n        leg.receiveShadow = true;\n        chairGroup.add(leg);\n    }\n    \n    addLeg(1, 1);   \/\/ \u53f3\u5965\n    addLeg(1, -1);  \/\/ \u53f3\u524d\n    addLeg(-1, 1);  \/\/ \u5de6\u5965\n    addLeg(-1, -1); \/\/ \u5de6\u524d\n    \n    \/\/ Group\u81ea\u4f53\u306e\u4f4d\u7f6e\u306f\u3001\u30d4\u30dc\u30c3\u30c8\uff08\u539f\u70b9\uff09\u3092\u5e8a(Y=0)\u306b\u8a2d\u5b9a\n    chairGroup.position.set(x, 0, z); \n    \n    chairGroup.userData.id = furniture.length; \n    chairGroup.userData.name = `chair_${chairGroup.userData.id}`;\n    \n    roomGroup.add(chairGroup);\n    furniture.push(chairGroup); \n    \n    return chairGroup;\n}\n\/\/  7. 3D\u30e2\u30c7\u30eb\u30d5\u30a1\u30a4\u30eb(GLTF\/GLB)\u3092\u30ed\u30fc\u30c9\u3057\u30b7\u30fc\u30f3\u306b\u8ffd\u52a0\u3059\u308b\nfunction addLoadSculptedModel(url, x, y , z,rotationY = 0,scale = 1.0) {\n    if (!gltfLoader) {\n        console.error(\"GLTFLoader is not initialized.\");\n        return;\n    }\n    \n    console.log(`Loading model from: ${url}`);\n    \n    gltfLoader.load(\n        url,\n        function (gltf) {\n            const model = gltf.scene;\n            \n            \/\/ \u30e2\u30c7\u30eb\u5168\u4f53\u3092 roomGroup\u306e\u5b50\u3068\u3057\u3066\u914d\u7f6e\u3057\u3001\u30c9\u30e9\u30c3\u30b0\u53ef\u80fd\u306b\u3059\u308b\n            model.position.set(x, y, z); \n            model.rotation.y = rotationY; \/\/\u521d\u671f\u56de\u8ee2\u89d2\u5ea6\u3092\u9069\u7528\n            model.scale.set(scale, scale, scale); \/\/ \u30b9\u30b1\u30fc\u30eb\u3092\u9069\u7528\n            \/\/ \u65e2\u5b58\u306e\u5bb6\u5177\u3068\u540c\u3058\u30d7\u30ed\u30d1\u30c6\u30a3\u3092\u8a2d\u5b9a\n            model.userData.draggable = true;\n            model.userData.id = furniture.length; \n            model.userData.name = `sculpture_${model.userData.id}`;\n            \n            \/\/ \u5f71\u306e\u8a2d\u5b9a\u3068\u30de\u30c6\u30ea\u30a2\u30eb\u306e\u66f4\u65b0\n            model.traverse(function (child) {\n                if (child.isMesh) {\n                    child.castShadow = true;\n                    child.receiveShadow = true; \n                    \/\/ \u30e2\u30c7\u30eb\u306e\u30de\u30c6\u30ea\u30a2\u30eb\u304c\u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u306b\u53cd\u5fdc\u3059\u308b\u3088\u3046\u306b\u8a2d\u5b9a\n                    if (Array.isArray(child.material)) {\n                        child.material.forEach(m =&gt; m.needsUpdate = true);\n                    } else if (child.material) {\n                        child.material.needsUpdate = true;\n                    }\n                }\n            });\n            \n            roomGroup.add(model); \n            furniture.push(model);\n        },\n        undefined, \n        \/\/ \u30a8\u30e9\u30fc\u30cf\u30f3\u30c9\u30ea\u30f3\u30b0\n        function (error) {\n            console.error(`An error occurred while loading model: ${url}`, error);\n        }\n    );\n}\n\n\/\/ \u5b9f\u884c\ninit();\nanimate();\n\n<\/code><\/pre>\n\n\n<p><img decoding=\"async\" class=\"wp-image-49240\" style=\"width: 640px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-12.png\" alt=\"VS Code\u5b9f\u884c\u7d50\u679c\u30fc3D\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u8868\u793a\u306e\u78ba\u8a8d\"><\/p>\n\n\n\n<div class=\"wp-block-group has-lightyellow-background-color has-background is-layout-constrained wp-block-group-is-layout-constrained\" style=\"padding-top:10px;padding-right:20px;padding-bottom:10px;padding-left:20px\"><div class=\"wp-block-group__inner-container\">\n<p><img decoding=\"async\" class=\"wp-image-43032\" style=\"width: 32px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/09\/ddns-19.png\" alt=\"\u30ef\u30f3\u30dd\u30a4\u30f3\u30c8\u30d2\u30f3\u30c8\"><strong>three.js\u306eGLTFLoader\u3068BufferGeometry\u306b\u3064\u3044\u3066<\/strong><\/p>\n\n\n\n<p>three.js\u306eGLTFLoader\u30e9\u30a4\u30d6\u30e9\u30ea\u306f\u3001<strong>gLTF\u30d5\u30a1\u30a4\u30eb<\/strong>\uff08.gltf\u307e\u305f\u306f.glb\uff09\u3092\u30ed\u30fc\u30c9\u3059\u308b\u969b\u306b\u3001\u30e2\u30c7\u30eb\u306e\u30b8\u30aa\u30e1\u30c8\u30ea\u3092\u8868\u73fe\u3059\u308b\u305f\u3081\u306b<strong>BufferGeometry<\/strong>\u304c\u4f7f\u308f\u308c\u3066\u3044\u307e\u3059\u3002<br>gLTF\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\u81ea\u4f53\u304c\u3001\u30b8\u30aa\u30e1\u30c8\u30ea\u30c7\u30fc\u30bf\u3092\u30b3\u30f3\u30d1\u30af\u30c8\u306a\u30d0\u30a4\u30ca\u30ea\u30c7\u30fc\u30bf\uff08\u30d0\u30c3\u30d5\u30a1\uff09\u3068\u3057\u3066\u52b9\u7387\u7684\u306b\u683c\u7d0d\u3059\u308b\u3088\u3046\u306b\u8a2d\u8a08\u3055\u308c\u3066\u304a\u308a\u3001GLTFLoader\u306f\u3053\u308c\u3092\u76f4\u63a5BufferGeometry\u306e\u5c5e\u6027\u306b\u30de\u30c3\u30d4\u30f3\u30b0\u3057\u307e\u3059\u3002\u3057\u305f\u304c\u3063\u3066\u3001GLTFLoader\u3092\u4f7f\u7528\u3057\u3066\u30ed\u30fc\u30c9\u3055\u308c\u305f\u30e1\u30c3\u30b7\u30e5\u306e\u30b8\u30aa\u30e1\u30c8\u30ea\u30d7\u30ed\u30d1\u30c6\u30a3\u306f\u3001\u5e38\u306b<strong>THREE.BufferGeometry<\/strong>\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<\/div><\/div>\n\n\n\n<p>\u9f8d\u306e\u7f6e\u7269\u304c\u8868\u793a\u3055\u308c\u308c\u3070\u6b63\u3057\u304f\u52d5\u4f5c\u3057\u3066\u3044\u307e\u3059\u3002<br>\u5931\u6557\u3057\u305f\u5834\u5408\u306f\u8868\u793a\u3055\u308c\u307e\u305b\u3093\u306e\u3067\u3001dragon-3d-model-2.glb\u306e\u30d5\u30a1\u30a4\u30eb\u304c\u5b58\u5728\u3059\u308b\u304b\u3001\u3082\u3057\u304f\u306f\u30d7\u30ed\u30b0\u30e9\u30e0\u304c\u30a8\u30e9\u30fc\u3057\u3066\u3044\u307e\u3059\u306e\u3067\u518d\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">&nbsp;\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u79fb\u52d5\u6a5f\u80fd\uff08\u30c9\u30e9\u30c3\u30b0\uff06\u30c9\u30ed\u30c3\u30d7\uff09\u306e\u5b9f\u88c5<\/h3>\n\n\n\n<p>\u4eca\u307e\u3067\u306f\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u8a2d\u7f6e\u3067\u3057\u305f\u304c\u3001\u30de\u30a6\u30b9\u3067\u5bb6\u5177\u3092\u9078\u3093\u3067\u30c9\u30e9\u30c3\u30b0\uff06\u30c9\u30ed\u30c3\u30d7\u3067\u79fb\u52d5\u3055\u305b\u308b\u6a5f\u80fd\u3092\u5b9f\u88c5\u3057\u307e\u3059\u3002<br>\u3053\u3053\u3067\u306f\u3001Raycaster\uff08\u5149\u7dda\u6295\u5c04\uff09\u3068\u30c9\u30e9\u30c3\u30b0\uff06\u30c9\u30ed\u30c3\u30d7\u3092\u624b\u52d5\u3067\u5b9f\u88c5\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<div class=\"wp-block-luxe-blocks-topic\" style=\"margin-top:10px;margin-bottom:30px\"><div class=\"wp-block-luxe-blocks-topic-title\" style=\"color:#fff;background-color:#006edc;border:1px solid #006edc;padding:2px 14px;align-items:center\">main.js \u8ffd\u52a0\u5185\u5bb9<\/div><div class=\"wp-block-luxe-blocks-topic-content\" style=\"border:1px solid #006edc;padding:0px 15px 0px 15px\">\n\n<ul type=\"1\">\n\n<li>\u30c9\u30e9\u30c3\u30b0&amp;\u30c9\u30ed\u30c3\u30d7\u306b\u5fc5\u8981\u306a\u5909\u6570\u3092\u8ffd\u52a0<br>&nbsp;\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u4e2d\u5fc3\u3068\u30af\u30ea\u30c3\u30af\u4f4d\u7f6e\u306e\u30ba\u30ec\u3092\u5438\u53ce\u3059\u308b\u305f\u3081\u306bTHREE.Vector3()\u3092\u4f7f\u3044\u307e\u3059\u3002<\/li>\n\n\n<li>\/\/ === 1-9. \u30c9\u30e9\u30c3\u30b0\uff06\u30c9\u30ed\u30c3\u30d7\u6a5f\u80fd\u306e\u521d\u671f\u5316 ===<br>Raycaster\u3001\u30de\u30a6\u30b9\u30a4\u30d9\u30f3\u30c8\u306e\u30ea\u30b9\u30ca\u30fc\u3001\u305d\u3057\u3066\u30c9\u30e9\u30c3\u30b0\u306b\u4f7f\u7528\u3059\u308b\u4eee\u60f3\u7684\u306a\u5e73\u9762\uff08Plane\uff09\u3092\u521d\u671f\u5316\u3057\u307e\u3059\u3002<\/li>\n\n\n<li>\u30de\u30a6\u30b9\u30a4\u30d9\u30f3\u30c8\u95a2\u6570\u306e\u5b9f\u88c5<br>\u30c9\u30e9\u30c3\u30b0\uff06\u30c9\u30ed\u30c3\u30d7\u306e\u6838\u5fc3\u3068\u306a\u308b3\u3064\u306e\u30a4\u30d9\u30f3\u30c8\u30cf\u30f3\u30c9\u30e9\u30fc\u95a2\u6570\u3067\u3042\u308bonPointerDown()\u3001onPointerMove()\u3001onPointerUp()\u3092\u8ffd\u52a0\u3057\u307e\u3059\u3002<\/li>\n\n\n<li>&nbsp;\/\/ \u30de\u30a6\u30b9\u30a4\u30d9\u30f3\u30c8\u306e\u30ea\u30b9\u30ca\u30fc\u3092\u8ffd\u52a0<br>onPointerDown\u3001onPointerMove\u3001onPointerUp\u3092renderer.domElement.addEventListener()\u3067\u8ffd\u52a0\u3057\u307e\u3059\u3002<\/li>\n\n<\/ul>\n\n<\/div><\/div>\n\n\n<pre class=\"line-numbers highlight-code-move\"><code class=\"language-javascript\">\/\/ main.js\n\/\/ [main-005-move]\n\/\/ index.html \u306e importmap \u306e\u8a2d\u5b9a\u306b\u57fa\u3065\u304d\u3001\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\u3092\u30a4\u30f3\u30dd\u30fc\u30c8\nimport * as THREE from \"three\";\nimport { OrbitControls } from '.\/jsm\/controls\/OrbitControls.js';\nimport { GLTFLoader } from '.\/jsm\/loaders\/GLTFLoader.js';\n\n\/\/ \u5fc5\u8981\u306a\u5909\u6570\u3092\u30b0\u30ed\u30fc\u30d0\u30eb\u30b9\u30b3\u30fc\u30d7\u3067\u5b9a\u7fa9\nlet scene, camera, renderer, controls;\nlet roomGroup; \/\/ \u5e8a\u3001\u58c1\u3001\u5bb6\u5177\u3092\u307e\u3068\u3081\u308b\u30b0\u30eb\u30fc\u30d7\nlet gltfLoader; \/\/ GLTF\u30ed\u30fc\u30c0\u30fc\n\nconst roomSize = 10; \/\/ \u90e8\u5c4b\u306e\u30b5\u30a4\u30ba (10m x 10m)\nconst furniture = []; \/\/ \u8907\u6570\u306e\u5bb6\u5177\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u9806\u5e8f\u4ed8\u3051\u3057\u3066\u4fdd\u7ba1\n\n\/\/ --- \u30c9\u30e9\u30c3\u30b0&amp;\u30c9\u30ed\u30c3\u30d7\u306b\u5fc5\u8981\u306a\u5909\u6570 ---\nlet raycaster;\nlet mouse;\nlet isDragging = false; \/\/ \u79fb\u52d5\u4e2d\u30d5\u30e9\u30b0\nlet selectedObject = null;\nlet plane;\nlet offset = new THREE.Vector3();\n\n\/\/ 1. \u521d\u671f\u5316\u95a2\u6570\uff1a3D\u4e16\u754c\u306e\u571f\u53f0\u3092\u4f5c\u308b\nfunction init() {\n    \/\/=== 1-1. \u30b7\u30fc\u30f3 (Scene) \u306e\u4f5c\u6210 ===\n    scene = new THREE.Scene();\n    scene.background = new THREE.Color(0xf0f0f0);  \/\/ \u80cc\u666f\u8272\u3092\u8584\u3044\u30b0\u30ec\u30fc\u306b\u8a2d\u5b9a\n    roomGroup = new THREE.Group();\n    scene.add(roomGroup);\n    \/\/ \u5ea7\u6a19\u8ef8\u30d8\u30eb\u30d1\u30fc\u3092\u8ffd\u52a0\uff08X\u8ef8\uff1a\u8d64\u3001Y\u8ef8\uff1a\u7dd1\u3001Z\u8ef8\uff1a\u9752\uff09\n    const axesHelper = new THREE.AxesHelper(10); \/\/ \u30b5\u30a4\u30ba10\n    scene.add(axesHelper);\n\n    \/\/ === 1-2. \u30ab\u30e1\u30e9 (Camera) \u306e\u8a2d\u5b9a ===\n    const fov = 75; \/\/ \u8996\u91ce\u89d2 (Field of View)\n    const aspect = window.innerWidth \/ window.innerHeight;  \/\/ \u30a2\u30b9\u30da\u30af\u30c8\u6bd4\n    const near = 0.1; \/\/ \u63cf\u753b\u958b\u59cb\u8ddd\u96e2\n    const far = 1000; \/\/ \u63cf\u753b\u7d42\u4e86\u8ddd\u96e2\n    camera = new THREE.PerspectiveCamera(fov, aspect, near, far);\n    \/\/ \u30ab\u30e1\u30e9\u306e\u521d\u671f\u4f4d\u7f6e\u3092\u6c7a\u5b9a (X, Y, Z)\n    camera.position.set(10, 15, 15);\n    camera.lookAt(0, 0, 0); \/\/ \u539f\u70b9(0, 0, 0)\u3092\u898b\u308b\u3088\u3046\u306b\u8a2d\u5b9a\n\n    \/\/ === 1-3. \u30ec\u30f3\u30c0\u30e9\u30fc (Renderer) \u306e\u4f5c\u6210 ===\n    renderer = new THREE.WebGLRenderer({ antialias: true }); \/\/ \u30a2\u30f3\u30c1\u30a8\u30a4\u30ea\u30a2\u30b9\u3067\u63cf\u753b\u3092\u6ed1\u3089\u304b\u306b\n    renderer.setSize(window.innerWidth, window.innerHeight); \/\/ \u63cf\u753b\u30b5\u30a4\u30ba\u3092\u30a6\u30a3\u30f3\u30c9\u30a6\u30b5\u30a4\u30ba\u306b\u5408\u308f\u305b\u308b\n    renderer.outputEncoding = THREE.sRGBEncoding; \/\/ \u30ec\u30f3\u30c0\u30ea\u30f3\u30b0\u54c1\u8cea\u6539\u5584\n    renderer.shadowMap.enabled = true; \/\/ \u5f71\u306e\u63cf\u753b\u3092\u6709\u52b9\u5316\n\n    \/\/ GLTF\u30ed\u30fc\u30c0\u30fc\u306e\u521d\u671f\u5316\n    gltfLoader = new GLTFLoader(); \n\n    \/\/ \u751f\u6210\u3055\u308c\u305f&lt;canvas&gt;\u8981\u7d20\u3092HTML&lt;body&gt;\u306b\u8ffd\u52a0\n    document.body.appendChild(renderer.domElement);\n\n    \/\/ === 1-4. \u30ab\u30e1\u30e9\u64cd\u4f5c (OrbitControls) \u306e\u8a2d\u5b9a ===\n    \/\/ \u30a4\u30f3\u30dd\u30fc\u30c8\u3057\u305f OrbitControls \u3092\u4f7f\u3063\u3066\u3001\u30de\u30a6\u30b9\u3067\u30ab\u30e1\u30e9\u3092\u52d5\u304b\u305b\u308b\u3088\u3046\u306b\u3059\u308b\n    controls = new OrbitControls(camera, renderer.domElement);\n    controls.enableDamping = true;  \/\/ \u52d5\u304d\u3092\u6ed1\u3089\u304b\u306b\u3059\u308b\n    controls.dampingFactor = 0.05;\n\n    \/\/ === 1-5. \u30e9\u30a4\u30c8 (Light) \u306e\u8ffd\u52a0 ===\n    \/\/ \u90e8\u5c4b\u5168\u4f53\u3092\u5747\u7b49\u306b\u7167\u3089\u3059\u74b0\u5883\u5149\n    const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); \/\/ \u5f31\u3081\u306e\u5149\n    scene.add(ambientLight);\n\n    \/\/ \u7279\u5b9a\u306e\u65b9\u5411\u304b\u3089\u7167\u3089\u3059\u6307\u5411\u6027\u5149\uff08\u5f71\u3092\u843d\u3068\u3059\u305f\u3081\u306b\u5fc5\u8981\uff09\n    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);\n    directionalLight.position.set(20, 30, 10);\n    scene.add(directionalLight);\n\n    \/\/ === 1-6 &amp; 1-7. \u90e8\u5c4b\u306e\u69cb\u9020\uff08\u5e8a\u3068\u58c1\uff09\u3068\u30b0\u30ea\u30c3\u30c9\u5b9a\u898f\u306e\u4f5c\u6210 ===\n    createRoomStructure();\n\n    \/\/ === 1-8. \u5bb6\u5177\uff08\u30d7\u30ec\u30fc\u30b9\u30db\u30eb\u30c0\u30fc\uff09\u306e\u4f5c\u6210\u3068\u914d\u7f6e ===\n    \/\/ \u5bb6\u5177\u306e\u914d\u7f6e\u4f8b\n    const deskHeight = 0.75;\n    const chairHeight = 0.5;\n\n    addFurniture(2, 2, 1, 3, 2.0, 0xa0522d); \/\/ \u68da\n    addFurniture(-3, -3, 3, 1.5, deskHeight, 0xdeb887); \/\/ \u30c7\u30b9\u30af\n    \/\/addFurniture(-3, -1, 0.5, 0.5, chairHeight, 0x800000); \/\/ \u30c1\u30a7\u30a2\n    addChair(-3, -1, 0x800000); \/\/ \u30c1\u30a7\u30a2\n\n    \/\/ \u30b9\u30ab\u30eb\u30d7\u30c8\u30e2\u30c7\u30eb(\u9f8d)\u306e\u30ed\u30fc\u30c9\u3068\u914d\u7f6e\n    addLoadSculptedModel('.\/dragon-3d-model-2.glb',-3, 1.3,-2.8,Math.PI \/ 2,2.0);\n\n    \/\/ === 1-9. \u30c9\u30e9\u30c3\u30b0\uff06\u30c9\u30ed\u30c3\u30d7\u6a5f\u80fd\u306e\u521d\u671f\u5316 ===\n    raycaster = new THREE.Raycaster();\n    mouse = new THREE.Vector2();\n    plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0); \n\n    \/\/ \u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u30fc\n    renderer.domElement.addEventListener('pointerdown', onPointerDown, false);\n    renderer.domElement.addEventListener('pointermove', onPointerMove, false);\n    renderer.domElement.addEventListener('pointerup', onPointerUp, false);\n    \n    window.addEventListener('resize', onWindowResize, false);\n}\n\n\/\/ 2. \u63cf\u753b\u30eb\u30fc\u30d7\u95a2\u6570\uff1a\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u306e\u5fc3\u81d3\u90e8\nfunction animate() {\n    requestAnimationFrame(animate); \/\/ \u30d6\u30e9\u30a6\u30b6\u306e\u518d\u63cf\u753b\u30bf\u30a4\u30df\u30f3\u30b0\u306b\u5408\u308f\u305b\u3066\u30eb\u30fc\u30d7\u3092\u7d99\u7d9a\n    controls.update();\/\/ \u30ab\u30e1\u30e9\u64cd\u4f5c\u306e\u30c0\u30f3\u30d4\u30f3\u30b0\u52b9\u679c\u3092\u9069\u7528\u3059\u308b\u305f\u3081\u306b\u66f4\u65b0\u304c\u5fc5\u8981\n    renderer.render(scene, camera); \/\/ \u30b7\u30fc\u30f3\u3092\u30ab\u30e1\u30e9\u306e\u8996\u70b9\u304b\u3089\u63cf\u753b \n}\n\n\/\/ 3. \u30a6\u30a3\u30f3\u30c9\u30a6\u30ea\u30b5\u30a4\u30ba\u51e6\u7406\nfunction onWindowResize() {\n    camera.aspect = window.innerWidth \/ window.innerHeight;    \/\/ \u30ab\u30e1\u30e9\u306e\u30a2\u30b9\u30da\u30af\u30c8\u6bd4\u66f4\u65b0\n    camera.updateProjectionMatrix(); \/\/ \u30ab\u30e1\u30e9\u306e\u6295\u5f71\u884c\u5217\u3092\u66f4\u65b0\n    renderer.setSize(window.innerWidth, window.innerHeight); \/\/ \u30ec\u30f3\u30c0\u30e9\u30fc\u306e\u30b5\u30a4\u30ba\u66f4\u65b0\n}\n\n\/\/ 4.\u90e8\u5c4b\u5168\u4f53\u69cb\u9020\u306e\u4f5c\u6210\n\nfunction createRoomStructure() {\n    const wallHeight = 2; \n\n    \/\/ \u5e8a\u306e\u4f5c\u6210\n    const floorGeometry = new THREE.PlaneGeometry(roomSize, roomSize); \n    const floorMaterial = new THREE.MeshStandardMaterial({ \n        color: 0xf8feff,\n        side: THREE.DoubleSide\n    });\n    const floor = new THREE.Mesh(floorGeometry, floorMaterial);\n    floor.rotation.x = Math.PI \/ 2;\n    floor.position.y = 0; \n    floor.receiveShadow = true; \n    roomGroup.add(floor); \n    \n    \/\/ \u8996\u899a\u7684\u5b9a\u898f\uff08GridHelper\uff09\u306e\u8ffd\u52a0 (1m\u9593\u9694)\n    const gridHelper = new THREE.GridHelper(\n        roomSize, roomSize, 0x444444, 0x888888        \n    );\n    gridHelper.position.y = 0.01; \n    roomGroup.add(gridHelper); \n\n    \/\/ \u58c1\u306e\u534a\u900f\u660e\u30de\u30c6\u30ea\u30a2\u30eb\u3092\u4f5c\u6210 \n    const wallMaterial = new THREE.MeshStandardMaterial({ \n        color: 0xf0e68c, \n        transparent: true, \n        opacity: 0.3,      \n        side: THREE.DoubleSide \n    });\n    \n    \/\/ \u58c1\u306e\u4f5c\u6210\u30d8\u30eb\u30d1\u30fc\n    function createWall(x, z, length, height, rotationY) {\n        const wallGeometry = new THREE.BoxGeometry(length, height, 0.1); \n        const wall = new THREE.Mesh(wallGeometry, wallMaterial); \n        \n        wall.position.y = height \/ 2;\n        wall.position.x = x;\n        wall.position.z = z;\n        wall.rotation.y = rotationY;\n        wall.receiveShadow = true;\n        roomGroup.add(wall); \n    }\n    \n    \/\/ 4\u3064\u306e\u58c1\u3092\u4f5c\u6210\n    createWall(0, -roomSize \/ 2, roomSize, wallHeight, 0); \n    createWall(0, roomSize \/ 2, roomSize, wallHeight, 0); \n    createWall(-roomSize \/ 2, 0, roomSize, wallHeight, Math.PI \/ 2); \n    createWall(roomSize \/ 2, 0, roomSize, wallHeight, Math.PI \/ 2);  \n}\n\n\/\/ 5.\u5358\u7d14\u306a\u5bb6\u5177\uff08BoxGeometry\uff09\u3092\u8ffd\u52a0\u3059\u308b\nfunction addFurniture(x, z, width, depth, height, color) {\n    \/\/ BoxGeometry: \u7acb\u65b9\u4f53\/\u76f4\u65b9\u4f53\u306e\u5f62\u72b6\n    const geometry = new THREE.BoxGeometry(width, height, depth); \n    const material = new THREE.MeshStandardMaterial({ color: color });\n    const mesh = new THREE.Mesh(geometry, material);\n    \n    mesh.position.set(x, height \/ 2, z); \n    mesh.castShadow = true; \n    mesh.receiveShadow = true;\n    \/\/ \u5f8c\u3067\u4fdd\u5b58\u30fb\u5143\u306e\u4f4d\u7f6e\u306b\u623b\u3059\u6642\u306b\u4e00\u8cab\u6027\u3092\u4fdd\u3064ID\u3092\u8a2d\u5b9a\u3057\u3066\u304a\u304f\n    mesh.userData.draggable = true;\n    mesh.userData.id = furniture.length; \n    mesh.userData.name = `furniture_${mesh.userData.id}`;\n\n    roomGroup.add(mesh); \/\/ roomGroup\u306b\u8ffd\u52a0\n    furniture.push(mesh); \/\/ \u5bb6\u5177\u306e\u4f4d\u7f6e\u72b6\u614b\u3092\u4fdd\u7ba1\n\n    return mesh;\n}\n\n\/\/ 6.\u8907\u5408\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\uff08\u6905\u5b50\uff09\u3092\u8ffd\u52a0\u3059\u308b\u3002\u8907\u6570\u306eMesh\u3092THREE.Group\u306b\u307e\u3068\u3081\u307e\u3059\u3002\n\nfunction addChair(x, z, color) {\n    const CHAIR_W = 0.5;\n    const CHAIR_D = 0.5;\n    const SEAT_H = 0.05;\n    const SEAT_Y = 0.5; \/\/ \u5ea7\u9762\u9ad8\u3055\uff08\u5e8a\u304b\u3089\u306e\u8ddd\u96e2\uff09\n    const LEG_D = 0.05;\n    const BACK_H = 0.4;\n    \n    const chairGroup = new THREE.Group();\n    chairGroup.userData.draggable = true;\n    chairGroup.userData.isComposite = true; \/\/ \u8907\u5408\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30d5\u30e9\u30b0\n    \n    \/\/ \u5168\u3066\u306e\u5b50\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306b\u5171\u901a\u306e\u6750\u8cea\u3092\u9069\u7528\n    const material = new THREE.MeshStandardMaterial({ color: color });\n\n    \/\/ 1. \u5ea7\u9762\n    const seatGeometry = new THREE.BoxGeometry(CHAIR_W, SEAT_H, CHAIR_D);\n    const seat = new THREE.Mesh(seatGeometry, material);\n    \/\/ \u5ea7\u9762\u306e\u4e2d\u5fc3\u304cY=SEAT_Y\u306b\u306a\u308b\u3088\u3046\u306b\u914d\u7f6e\n    seat.position.y = SEAT_Y - SEAT_H \/ 2;\n    seat.castShadow = true; \n    seat.receiveShadow = true;\n    chairGroup.add(seat);\n\n    \/\/ 2. \u80cc\u3082\u305f\u308c\n    const backGeometry = new THREE.BoxGeometry(CHAIR_W, BACK_H, 0.05); \/\/ \u5965\u884c\u304d 5cm\n    const back = new THREE.Mesh(backGeometry, material);\n    \/\/ Y\u4f4d\u7f6e: \u5ea7\u9762\u306e\u4e0a\u9762 (SEAT_Y) + \u80cc\u3082\u305f\u308c\u9ad8\u3055\u306e\u534a\u5206 (BACK_H\/2)\n    \/\/ Z\u4f4d\u7f6e: \u6905\u5b50\u306e\u5965\u884c\u304d\u534a\u5206 (CHAIR_D\/2) - \u80cc\u3082\u305f\u308c\u306e\u5965\u884c\u304d\u534a\u5206 (0.05\/2)\n    back.position.set(0, SEAT_Y + BACK_H \/ 2, CHAIR_D \/ 2 - 0.05 \/ 2);\n    back.castShadow = true;\n    back.receiveShadow = true;\n    chairGroup.add(back);\n\n    \/\/ 3. 4\u672c\u306e\u811a\n    const legH = SEAT_Y - SEAT_H; \/\/ \u811a\u306e\u9ad8\u3055\u306f\u5e8a\u304b\u3089\u5ea7\u9762\u306e\u4e0b\u307e\u3067\n    const legGeometry = new THREE.BoxGeometry(LEG_D, legH, LEG_D);\n    \n    function addLeg(lx, lz) {\n        const leg = new THREE.Mesh(legGeometry, material);\n        \/\/ X\/Z\u4f4d\u7f6e: \u6905\u5b50\u306e\u5e45\/\u5965\u884c\u304d\u304b\u3089\u3001\u811a\u306e\u5965\u884c\u304d\/\u5e45\u306e\u534a\u5206\u3092\u5f15\u3044\u305f\u4f4d\u7f6e\n        \/\/ Y\u4f4d\u7f6e: \u811a\u306e\u9ad8\u3055\u306e\u534a\u5206 (legH\/2)\n        leg.position.set(\n            lx * (CHAIR_W \/ 2 - LEG_D \/ 2), \n            legH \/ 2, \n            lz * (CHAIR_D \/ 2 - LEG_D \/ 2)\n        );\n        leg.castShadow = true; \n        leg.receiveShadow = true;\n        chairGroup.add(leg);\n    }\n    \n    addLeg(1, 1);   \/\/ \u53f3\u5965\n    addLeg(1, -1);  \/\/ \u53f3\u524d\n    addLeg(-1, 1);  \/\/ \u5de6\u5965\n    addLeg(-1, -1); \/\/ \u5de6\u524d\n    \n    \/\/ Group\u81ea\u4f53\u306e\u4f4d\u7f6e\u306f\u3001\u30d4\u30dc\u30c3\u30c8\uff08\u539f\u70b9\uff09\u3092\u5e8a(Y=0)\u306b\u8a2d\u5b9a\n    chairGroup.position.set(x, 0, z); \n    \n    chairGroup.userData.id = furniture.length; \n    chairGroup.userData.name = `chair_${chairGroup.userData.id}`;\n    \n    roomGroup.add(chairGroup);\n    furniture.push(chairGroup); \n    \n    return chairGroup;\n}\n\n\/\/  7. 3D\u30e2\u30c7\u30eb\u30d5\u30a1\u30a4\u30eb(GLTF\/GLB)\u3092\u30ed\u30fc\u30c9\u3057\u30b7\u30fc\u30f3\u306b\u8ffd\u52a0\u3059\u308b\nfunction addLoadSculptedModel(url, x, y , z,rotationY = 0,scale = 1.0) {\n    if (!gltfLoader) {\n        console.error(\"GLTFLoader is not initialized.\");\n        return;\n    }\n    \n    console.log(`Loading model from: ${url}`);\n    \n    gltfLoader.load(\n        url,\n        function (gltf) {\n            const model = gltf.scene;\n            \n            \/\/ \u30e2\u30c7\u30eb\u5168\u4f53\u3092 roomGroup\u306e\u5b50\u3068\u3057\u3066\u914d\u7f6e\u3057\u3001\u30c9\u30e9\u30c3\u30b0\u53ef\u80fd\u306b\u3059\u308b\n            model.position.set(x, y, z); \n            model.rotation.y = rotationY; \/\/\u521d\u671f\u56de\u8ee2\u89d2\u5ea6\u3092\u9069\u7528\n            model.scale.set(scale, scale, scale); \/\/ \u30b9\u30b1\u30fc\u30eb\u3092\u9069\u7528\n            \/\/ \u65e2\u5b58\u306e\u5bb6\u5177\u3068\u540c\u3058\u30d7\u30ed\u30d1\u30c6\u30a3\u3092\u8a2d\u5b9a\n            model.userData.draggable = true;\n            model.userData.id = furniture.length; \n            model.userData.name = `sculpture_${model.userData.id}`;\n            \n            \/\/ \u5f71\u306e\u8a2d\u5b9a\u3068\u30de\u30c6\u30ea\u30a2\u30eb\u306e\u66f4\u65b0\n            model.traverse(function (child) {\n                if (child.isMesh) {\n                    child.castShadow = true;\n                    child.receiveShadow = true;\n                    \/\/ \u30e2\u30c7\u30eb\u306e\u30de\u30c6\u30ea\u30a2\u30eb\u304c\u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u306b\u53cd\u5fdc\u3059\u308b\u3088\u3046\u306b\u8a2d\u5b9a\n                    if (Array.isArray(child.material)) {\n                        child.material.forEach(m =&gt; m.needsUpdate = true);\n                    } else if (child.material) {\n                        child.material.needsUpdate = true;\n                    }\n                }\n            });\n            \n            roomGroup.add(model); \n            furniture.push(model);\n        },\n        undefined, \n        \/\/ \u30a8\u30e9\u30fc\u30cf\u30f3\u30c9\u30ea\u30f3\u30b0\n        function (error) {\n            console.error(`An error occurred while loading model: ${url}`, error);\n        }\n    );\n}\n\/\/ 8. --- \u30de\u30a6\u30b9\u30a4\u30d9\u30f3\u30c8\u30cf\u30f3\u30c9\u30e9\u30fc ---\n\nfunction updateMouse(event) {\n    const rect = renderer.domElement.getBoundingClientRect();\n    mouse.x = ((event.clientX - rect.left) \/ rect.width) * 2 - 1;\n    mouse.y = -((event.clientY - rect.top) \/ rect.height) * 2 + 1;\n}\n\n\/\/ 9. \u30de\u30a6\u30b9\u30dc\u30bf\u30f3\u304c\u62bc\u3055\u308c\u305f\u3068\u304d (\u30c9\u30e9\u30c3\u30b0)\nfunction onPointerDown(event) {\n    updateMouse(event);\n\n    raycaster.setFromCamera(mouse, camera);\n    \/\/ Raycasting\u306e\u5bfe\u8c61\u3092roomGroup\u306e\u5b50\u8981\u7d20\u306b\u9650\u5b9a\n    const intersects = raycaster.intersectObjects(roomGroup.children, true);\n\n    if (intersects.length &gt; 0) {\n        let hitObject = intersects[0].object;\n\n        \/\/ \u8907\u5408\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3001GLTF\u30e2\u30c7\u30eb\u306e\u5b50\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u304c\u30d2\u30c3\u30c8\u3057\u305f\u5834\u5408\u3001\u89aa\uff08Group\/Scene\uff09\u3092\u9078\u629e\n        while (hitObject.parent &amp;&amp; !hitObject.userData.draggable &amp;&amp; hitObject.parent !== roomGroup) {\n            hitObject = hitObject.parent;\n        }\n\n        \/\/ \u5358\u7d14\u306aBoxGeometry\uff08\u30c7\u30b9\u30af\u3084\u68da\uff09\u304c\u76f4\u63a5\u5f53\u305f\u3063\u305f\u5834\u5408\n        if (hitObject.userData.draggable) { \n            selectedObject = hitObject;\n        } else {\n             \/\/ \u5f53\u305f\u3063\u305f\u304c\u3001\u30c9\u30e9\u30c3\u30b0\u4e0d\u53ef\uff08\u4f8b\uff1a\u5e8a\uff09\u306e\u5834\u5408\n            selectedObject = null;\n            return;\n        }\n\n        \/\/ selectedObject \u306e Y\u4f4d\u7f6e (\u30d4\u30dc\u30c3\u30c8\u306e\u4f4d\u7f6e) \u3092\u53d6\u5f97\n        const objectY = selectedObject.position.y; \n\n        isDragging = true;\n           \n        \/\/ \u79fb\u52d5\u30e2\u30fc\u30c9\u306e\u5834\u5408\u306e\u307f\u30aa\u30d5\u30bb\u30c3\u30c8\u3092\u8a08\u7b97\n        if (raycaster.ray.intersectPlane(plane, offset)) {\n            offset.sub(selectedObject.position); \n        }\n\n        controls.enabled = false;\n    } else {\n        \/\/ \u4f55\u3082\u9078\u629e\u3055\u308c\u306a\u304b\u3063\u305f\u5834\u5408\u306f\u3001\u9078\u629e\u3092\u89e3\u9664\u3059\u308b\n        selectedObject = null;\n        isDragging = false;\n        controls.enabled = true;\n    }\n}\n\n\/\/ 10.\u30de\u30a6\u30b9\u304c\u79fb\u52d5\u3057\u305f\u3068\u304d (\u30c9\u30e9\u30c3\u30b0\u4e2d)\nfunction onPointerMove(event) {\n    if (!selectedObject) return;\n\n    updateMouse(event);\n    raycaster.setFromCamera(mouse, camera);\n    \n    if (isDragging) { \/\/ === \u79fb\u52d5\u30ed\u30b8\u30c3\u30af ===\n        let intersection = new THREE.Vector3();\n        if (raycaster.ray.intersectPlane(plane, intersection)) {\n            selectedObject.position.copy(intersection.sub(offset));\n            selectedObject.position.y = selectedObject.geometry.parameters.height \/ 2;\n        }\n    } \n}\n\n\/\/ 11.\u30de\u30a6\u30b9\u30dc\u30bf\u30f3\u304c\u96e2\u3055\u308c\u305f\u3068\u304d (\u7d42\u4e86)\nfunction onPointerUp(event) {\n    if (isDragging) { \n        isDragging = false;\n        selectedObject = null;\n        \n        \/\/ \u30ab\u30e1\u30e9\u64cd\u4f5c\u3092\u518d\u6709\u52b9\u5316\n        controls.enabled = true;\n    }\n}\n\n\/\/ \u5b9f\u884c\ninit();\nanimate();\n\n<\/code><\/pre>\n\n\n<p><img decoding=\"async\" class=\"wp-image-49244\" style=\"width: 640px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-13.png\" alt=\"VS Code\u5b9f\u884c\u7d50\u679c\u30fc\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u79fb\u52d5\"><\/p>\n\n\n\n<p>\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u30de\u30a6\u30b9\u306e\u5de6\u30af\u30ea\u30c3\u30af\u3067\u3064\u307e\u3093\u3067\u79fb\u52d5\u3055\u305b\u308b\u3053\u3068\u304c\u3067\u304d\u308c\u3070\u52d5\u4f5c\u306f\u6b63\u5e38\u3067\u3059\u3002\u6c34\u5e73\u9762\u306b\u5bfe\u3057\u3066\u306e\u307f\u79fb\u52d5\u3055\u305b\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u56de\u8ee2\u6a5f\u80fd\u306e\u5b9f\u88c5<\/h3>\n\n\n\n<p>\u5e73\u9762\u4e0a\u3067\u306e\u79fb\u52d5\u304c\u3067\u304d\u307e\u3057\u305f\u306e\u3067\u3001\u56de\u8ee2\u6a5f\u80fd\u3092\u5b9f\u88c5\u3057\u307e\u3059\u3002<br>\u56de\u8ee2\u64cd\u4f5c\u3092\u8996\u899a\u7684\u306b\u884c\u3044\u305f\u3044\u306e\u3067\u3001\u56de\u8ee2\u30ac\u30a4\u30c9\u30ea\u30f3\u30b0\u3001\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306eX,Y\u4e2d\u5fc3\u8ef8\u5ef6\u9577\u8868\u793a\u3082\u8ffd\u52a0\u3057\u307e\u3059\u3002\u64cd\u4f5c\u306f\u3053\u306e\u56de\u8ee2\u30ac\u30a4\u30c9\u30ea\u30f3\u30b0\u3092\u30de\u30a6\u30b9\u3067\u3064\u307e\u3093\u3067\u56de\u8ee2\u3055\u305b\u308b\u3088\u3046\u306b\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<div class=\"wp-block-luxe-blocks-topic\" style=\"margin-top:10px;margin-bottom:30px\"><div class=\"wp-block-luxe-blocks-topic-title\" style=\"color:#fff;background-color:#006edc;border:1px solid #006edc;padding:2px 14px;align-items:center\">main.js \u8ffd\u52a0\u5185\u5bb9<\/div><div class=\"wp-block-luxe-blocks-topic-content\" style=\"border:1px solid #006edc;padding:0px 15px 0px 15px\">\n\n<ul type=\"1\">\n\n<li>\/\/ === 1-10. \u56de\u8ee2\u30ac\u30a4\u30c9\u30ea\u30f3\u30b0\u306e\u521d\u671f\u5316 ===<br>createRotationGuide()\u306e\u547c\u3073\u51fa\u3057\u3002<\/li>\n\n\n<li>createRotationGuide()\u306e\u8ffd\u52a0<br>\u56de\u8ee2\u30ac\u30a4\u30c9\uff08\u30ea\u30f3\u30b0\u3068\u76ee\u76db\uff09\u3092\u4f5c\u6210\u3059\u308b<\/li>\n\n\n<li>updateExtensionLines\u306e\u8ffd\u52a0<br>&nbsp;\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u73fe\u5728\u306e\u56de\u8ee2\u306b\u5408\u308f\u305b\u3066\u5f15\u304d\u51fa\u3057\u30ac\u30a4\u30c9\u7dda\u3092\u4f5c\u6210\u30fb\u66f4\u65b0\u3059\u308b\u3002<\/li>\n\n\n<li>\u56de\u8ee2\u64cd\u4f5c\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u30fc\u306e\u8ffd\u52a0<br>Raycaster\u3001\u30de\u30a6\u30b9\u30a4\u30d9\u30f3\u30c8\u306e\u30ea\u30b9\u30ca\u30fc\u3001\u305d\u3057\u3066\u30c9\u30e9\u30c3\u30b0\u306b\u4f7f\u7528\u3059\u308b\u4eee\u60f3\u7684\u306a\u5e73\u9762\uff08Plane\uff09\u3092\u521d\u671f\u5316\u3057\u307e\u3059\u3002<\/li>\n\n\n<li>\u30de\u30a6\u30b9\u30a4\u30d9\u30f3\u30c8\u95a2\u6570\u306e\u4fee\u6b63<br>\u30c9\u30e9\u30c3\u30b0\u4e2d\u306b\u7279\u5b9a\u306e\u30ad\u30fc\uff08Shift \u30ad\u30fc\uff09\u3092\u62bc\u3057\u3066\u3044\u308b\u9593\u306b\u56de\u8ee2\u3059\u308b\u3088\u3046\u306b onPointerMove\u3092\u6539\u9020\u3057\u307e\u3059\u3002\u307e\u305f\u56de\u8ee2\u30ea\u30f3\u30b0\u306e\u8868\u793a\u3001\u4e2d\u5fc3\u7dda\u306e\u30ac\u30a4\u30c9\u8868\u793a\u3082\u884c\u3044\u307e\u3059\u3002<br>\u30de\u30a6\u30b9\u304c\u79fb\u52d5\u3057\u305f\u3068\u304d\u3001\u30c9\u30e9\u30c3\u30b0\u4e2d\/\u56de\u8ee2\u4e2d\u3067\u3042\u308b\u304b\u306e\u5224\u5b9a\u3082\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059\u306e\u3067\u3001\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u306e\u5909\u66f4\u7b87\u6240\u3092\u53c2\u8003\u306b\u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/li>\n\n<\/ul>\n\n<\/div><\/div>\n\n\n<pre class=\"line-numbers highlight-code-rotate\"><code class=\"language-javascript\">\/\/ main.js\n\/\/ [main-006-rotate]\n\/\/ index.html \u306e importmap \u306e\u8a2d\u5b9a\u306b\u57fa\u3065\u304d\u3001\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\u3092\u30a4\u30f3\u30dd\u30fc\u30c8\nimport * as THREE from \"three\";\nimport { OrbitControls } from '.\/jsm\/controls\/OrbitControls.js';\nimport { GLTFLoader } from '.\/jsm\/loaders\/GLTFLoader.js';\n\n\/\/ \u5fc5\u8981\u306a\u5909\u6570\u3092\u30b0\u30ed\u30fc\u30d0\u30eb\u30b9\u30b3\u30fc\u30d7\u3067\u5b9a\u7fa9\nlet scene, camera, renderer, controls;\nlet roomGroup; \/\/ \u5e8a\u3001\u58c1\u3001\u5bb6\u5177\u3092\u307e\u3068\u3081\u308b\u30b0\u30eb\u30fc\u30d7\nlet gltfLoader; \/\/ GLTF\u30ed\u30fc\u30c0\u30fc\n\nconst roomSize = 10; \/\/ \u90e8\u5c4b\u306e\u30b5\u30a4\u30ba (10m x 10m)\nconst furniture = []; \/\/ \u8907\u6570\u306e\u5bb6\u5177\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u9806\u5e8f\u4ed8\u3051\u3057\u3066\u4fdd\u7ba1\n\n\/\/ --- \u30c9\u30e9\u30c3\u30b0&amp;\u30c9\u30ed\u30c3\u30d7\u306b\u5fc5\u8981\u306a\u5909\u6570 ---\nlet raycaster;\nlet mouse;\nlet isDragging = false; \/\/ \u79fb\u52d5\u4e2d\u30d5\u30e9\u30b0\nlet selectedObject = null;\nlet plane;\nlet offset = new THREE.Vector3();\n\/\/ --- \u56de\u8ee2\u306b\u5fc5\u8981\u306a\u5909\u6570 ---\nlet dragPlane;\nlet isRotating = false; \nlet rotationGuide = null;\n\n\/\/ 1. \u521d\u671f\u5316\u95a2\u6570\uff1a3D\u4e16\u754c\u306e\u571f\u53f0\u3092\u4f5c\u308b\nfunction init() {\n    \/\/=== 1-1. \u30b7\u30fc\u30f3 (Scene) \u306e\u4f5c\u6210 ===\n    scene = new THREE.Scene();\n    scene.background = new THREE.Color(0xf0f0f0);  \/\/ \u80cc\u666f\u8272\u3092\u8584\u3044\u30b0\u30ec\u30fc\u306b\u8a2d\u5b9a\n    roomGroup = new THREE.Group();\n    scene.add(roomGroup);\n\n    \/\/ \u5ea7\u6a19\u8ef8\u30d8\u30eb\u30d1\u30fc\u3092\u8ffd\u52a0\uff08X\u8ef8\uff1a\u8d64\u3001Y\u8ef8\uff1a\u7dd1\u3001Z\u8ef8\uff1a\u9752\uff09\n    const axesHelper = new THREE.AxesHelper(10); \/\/ \u30b5\u30a4\u30ba10\n    scene.add(axesHelper);\n\n    \/\/ === 1-2. \u30ab\u30e1\u30e9 (Camera) \u306e\u8a2d\u5b9a ===\n    const fov = 75; \/\/ \u8996\u91ce\u89d2 (Field of View)\n    const aspect = window.innerWidth \/ window.innerHeight;  \/\/ \u30a2\u30b9\u30da\u30af\u30c8\u6bd4\n    const near = 0.1; \/\/ \u63cf\u753b\u958b\u59cb\u8ddd\u96e2\n    const far = 1000; \/\/ \u63cf\u753b\u7d42\u4e86\u8ddd\u96e2\n    camera = new THREE.PerspectiveCamera(fov, aspect, near, far);\n    \/\/ \u30ab\u30e1\u30e9\u306e\u521d\u671f\u4f4d\u7f6e\u3092\u6c7a\u5b9a (X, Y, Z)\n    camera.position.set(10, 15, 15);\n    camera.lookAt(0, 0, 0); \/\/ \u539f\u70b9(0, 0, 0)\u3092\u898b\u308b\u3088\u3046\u306b\u8a2d\u5b9a\n\n    \/\/ === 1-3. \u30ec\u30f3\u30c0\u30e9\u30fc (Renderer) \u306e\u4f5c\u6210 ===\n    renderer = new THREE.WebGLRenderer({ antialias: true }); \/\/ \u30a2\u30f3\u30c1\u30a8\u30a4\u30ea\u30a2\u30b9\u3067\u63cf\u753b\u3092\u6ed1\u3089\u304b\u306b\n    renderer.setSize(window.innerWidth, window.innerHeight); \/\/ \u63cf\u753b\u30b5\u30a4\u30ba\u3092\u30a6\u30a3\u30f3\u30c9\u30a6\u30b5\u30a4\u30ba\u306b\u5408\u308f\u305b\u308b\n    \n    renderer.outputEncoding = THREE.sRGBEncoding; \/\/ \u30ec\u30f3\u30c0\u30ea\u30f3\u30b0\u54c1\u8cea\u6539\u5584\n    renderer.shadowMap.enabled = true; \/\/ \u5f71\u306e\u63cf\u753b\u3092\u6709\u52b9\u5316\n\n    \/\/ GLTF\u30ed\u30fc\u30c0\u30fc\u306e\u521d\u671f\u5316\n    gltfLoader = new GLTFLoader(); \n\n    \/\/ \u751f\u6210\u3055\u308c\u305f&lt;canvas&gt;\u8981\u7d20\u3092HTML&lt;body&gt;\u306b\u8ffd\u52a0\n    document.body.appendChild(renderer.domElement);\n\n    \/\/ === 1-4. \u30ab\u30e1\u30e9\u64cd\u4f5c (OrbitControls) \u306e\u8a2d\u5b9a ===\n    \/\/ \u30a4\u30f3\u30dd\u30fc\u30c8\u3057\u305f OrbitControls \u3092\u4f7f\u3063\u3066\u3001\u30de\u30a6\u30b9\u3067\u30ab\u30e1\u30e9\u3092\u52d5\u304b\u305b\u308b\u3088\u3046\u306b\u3059\u308b\n    controls = new OrbitControls(camera, renderer.domElement);\n    controls.enableDamping = true;  \/\/ \u52d5\u304d\u3092\u6ed1\u3089\u304b\u306b\u3059\u308b\n    controls.dampingFactor = 0.05;\n\n    \/\/ === 1-5. \u30e9\u30a4\u30c8 (Light) \u306e\u8ffd\u52a0 ===\n    \/\/ \u90e8\u5c4b\u5168\u4f53\u3092\u5747\u7b49\u306b\u7167\u3089\u3059\u74b0\u5883\u5149\n    const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); \/\/ \u5f31\u3081\u306e\u5149\n    scene.add(ambientLight);\n\n    \/\/ \u7279\u5b9a\u306e\u65b9\u5411\u304b\u3089\u7167\u3089\u3059\u6307\u5411\u6027\u5149\uff08\u5f71\u3092\u843d\u3068\u3059\u305f\u3081\u306b\u5fc5\u8981\uff09\n    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);\n    directionalLight.position.set(20, 30, 10);\n    scene.add(directionalLight);\n\n    \/\/ === 1-6 &amp; 1-7. \u90e8\u5c4b\u306e\u69cb\u9020\uff08\u5e8a\u3068\u58c1\uff09\u3068\u30b0\u30ea\u30c3\u30c9\u5b9a\u898f\u306e\u4f5c\u6210 ===\n    createRoomStructure();\n\n    \/\/ === 1-8. \u5bb6\u5177\uff08\u30d7\u30ec\u30fc\u30b9\u30db\u30eb\u30c0\u30fc\uff09\u306e\u4f5c\u6210\u3068\u914d\u7f6e ===\n    \/\/ \u5bb6\u5177\u306e\u914d\u7f6e\u4f8b\n    const deskHeight = 0.75;\n    const chairHeight = 0.5;\n\n    addFurniture(2, 2, 1, 3, 2.0, 0xa0522d); \/\/ \u68da\n    addFurniture(-3, -3, 3, 1.5, deskHeight, 0xdeb887); \/\/ \u30c7\u30b9\u30af\n    \/\/addFurniture(-3, -1, 0.5, 0.5, chairHeight, 0x800000); \/\/ \u30c1\u30a7\u30a2\n    addChair(-3, -1, 0x800000); \/\/ \u30c1\u30a7\u30a2\n\n    \/\/ \u30b9\u30ab\u30eb\u30d7\u30c8\u30e2\u30c7\u30eb(\u9f8d)\u306e\u30ed\u30fc\u30c9\u3068\u914d\u7f6e\n    addLoadSculptedModel('.\/dragon-3d-model-2.glb',-3, 1.3,-2.8,Math.PI \/ 2,2.0);\n\n    \/\/ === 1-9. \u30c9\u30e9\u30c3\u30b0\uff06\u30c9\u30ed\u30c3\u30d7\u6a5f\u80fd\u306e\u521d\u671f\u5316 ===\n    raycaster = new THREE.Raycaster();\n    mouse = new THREE.Vector2();\n    plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0); \n    dragPlane = plane; \n    \/\/ === 1-10. \u56de\u8ee2\u30ac\u30a4\u30c9\u30ea\u30f3\u30b0\u306e\u521d\u671f\u5316 ===\n    rotationGuide = createRotationGuide(); \n\n    \/\/ \u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u30fc\n    renderer.domElement.addEventListener('pointerdown', onPointerDown, false);\n    renderer.domElement.addEventListener('pointermove', onPointerMove, false);\n    renderer.domElement.addEventListener('pointerup', onPointerUp, false);\n    \n    window.addEventListener('resize', onWindowResize, false);\n}\n\n\/\/ 2. \u63cf\u753b\u30eb\u30fc\u30d7\u95a2\u6570\uff1a\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u306e\u5fc3\u81d3\u90e8\nfunction animate() { \/\/ \u30ab\u30e1\u30e9\u306e\u30a2\u30b9\u30da\u30af\u30c8\u6bd4\u3092\u66f4\u65b0\n    requestAnimationFrame(animate); \/\/ \u30d6\u30e9\u30a6\u30b6\u306e\u518d\u63cf\u753b\u30bf\u30a4\u30df\u30f3\u30b0\u306b\u5408\u308f\u305b\u3066\u30eb\u30fc\u30d7\u3092\u7d99\u7d9a\n    controls.update();\/\/ \u30ab\u30e1\u30e9\u64cd\u4f5c\u306e\u30c0\u30f3\u30d4\u30f3\u30b0\u52b9\u679c\u3092\u9069\u7528\u3059\u308b\u305f\u3081\u306b\u66f4\u65b0\u304c\u5fc5\u8981\n    renderer.render(scene, camera); \/\/ \u30b7\u30fc\u30f3\u3092\u30ab\u30e1\u30e9\u306e\u8996\u70b9\u304b\u3089\u63cf\u753b \n}\n\n\/\/ 3. \u30a6\u30a3\u30f3\u30c9\u30a6\u30ea\u30b5\u30a4\u30ba\u51e6\u7406\nfunction onWindowResize() {\n    camera.aspect = window.innerWidth \/ window.innerHeight;    \/\/ \u30ab\u30e1\u30e9\u306e\u30a2\u30b9\u30da\u30af\u30c8\u6bd4\u66f4\u65b0\n    camera.updateProjectionMatrix(); \/\/ \u30ab\u30e1\u30e9\u306e\u6295\u5f71\u884c\u5217\u3092\u66f4\u65b0\n    renderer.setSize(window.innerWidth, window.innerHeight); \/\/ \u30ec\u30f3\u30c0\u30e9\u30fc\u306e\u30b5\u30a4\u30ba\u66f4\u65b0\n}\n\n\/\/ 4.\u90e8\u5c4b\u5168\u4f53\u69cb\u9020\u306e\u4f5c\u6210\nfunction createRoomStructure() {\n    const wallHeight = 2; \n\n    \/\/ \u5e8a\u306e\u4f5c\u6210\n    const floorGeometry = new THREE.PlaneGeometry(roomSize, roomSize); \n    const floorMaterial = new THREE.MeshStandardMaterial({ \n        color: 0xf8feff,\n        side: THREE.DoubleSide\n    });\n    const floor = new THREE.Mesh(floorGeometry, floorMaterial);\n    floor.rotation.x = Math.PI \/ 2;\n    floor.position.y = 0; \n    floor.receiveShadow = true; \n    roomGroup.add(floor); \n    \n    \/\/ \u8996\u899a\u7684\u5b9a\u898f\uff08GridHelper\uff09\u306e\u8ffd\u52a0 (1m\u9593\u9694)\n    const gridHelper = new THREE.GridHelper(\n        roomSize, roomSize, 0x444444, 0x888888        \n    );\n    gridHelper.position.y = 0.01; \n    roomGroup.add(gridHelper); \n\n    \/\/ \u58c1\u306e\u534a\u900f\u660e\u30de\u30c6\u30ea\u30a2\u30eb\u3092\u4f5c\u6210 \n    const wallMaterial = new THREE.MeshStandardMaterial({ \n        color: 0xf0e68c, \n        transparent: true, \n        opacity: 0.3,      \n        side: THREE.DoubleSide \n    });\n    \n    \/\/ \u58c1\u306e\u4f5c\u6210\u30d8\u30eb\u30d1\u30fc\n    function createWall(x, z, length, height, rotationY) {\n        const wallGeometry = new THREE.BoxGeometry(length, height, 0.1); \n        const wall = new THREE.Mesh(wallGeometry, wallMaterial); \n        \n        wall.position.y = height \/ 2;\n        wall.position.x = x;\n        wall.position.z = z;\n        wall.rotation.y = rotationY;\n        wall.receiveShadow = true;\n        roomGroup.add(wall); \n    }\n    \n    \/\/ 4\u3064\u306e\u58c1\u3092\u4f5c\u6210\n    createWall(0, -roomSize \/ 2, roomSize, wallHeight, 0); \n    createWall(0, roomSize \/ 2, roomSize, wallHeight, 0); \n    createWall(-roomSize \/ 2, 0, roomSize, wallHeight, Math.PI \/ 2); \n    createWall(roomSize \/ 2, 0, roomSize, wallHeight, Math.PI \/ 2);  \n}\n\n\/\/ 5.\u5358\u7d14\u306a\u5bb6\u5177\uff08BoxGeometry\uff09\u3092\u8ffd\u52a0\u3059\u308b\nfunction addFurniture(x, z, width, depth, height, color) {\n    \/\/ BoxGeometry: \u7acb\u65b9\u4f53\/\u76f4\u65b9\u4f53\u306e\u5f62\u72b6\n    const geometry = new THREE.BoxGeometry(width, height, depth); \n    const material = new THREE.MeshStandardMaterial({ color: color });\n    const mesh = new THREE.Mesh(geometry, material);\n    \n    mesh.position.set(x, height \/ 2, z); \n    mesh.castShadow = true; \n    mesh.receiveShadow = true;\n    \/\/ \u5f8c\u3067\u4fdd\u5b58\u30fb\u5143\u306e\u4f4d\u7f6e\u306b\u623b\u3059\u6642\u306b\u4e00\u8cab\u6027\u3092\u4fdd\u3064ID\u3092\u8a2d\u5b9a\u3057\u3066\u304a\u304f\n    mesh.userData.draggable = true;\n    mesh.userData.id = furniture.length; \n    mesh.userData.name = `furniture_${mesh.userData.id}`;\n\n    roomGroup.add(mesh); \/\/ roomGroup\u306b\u8ffd\u52a0\n    furniture.push(mesh); \/\/ \u5bb6\u5177\u306e\u4f4d\u7f6e\u72b6\u614b\u3092\u4fdd\u7ba1\n\n    return mesh;\n}\n\n\/\/ 6.\u8907\u5408\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\uff08\u6905\u5b50\uff09\u3092\u8ffd\u52a0\u3059\u308b\u3002\u8907\u6570\u306eMesh\u3092THREE.Group\u306b\u307e\u3068\u3081\u307e\u3059\u3002\nfunction addChair(x, z, color) {\n    const CHAIR_W = 0.5;\n    const CHAIR_D = 0.5;\n    const SEAT_H = 0.05;\n    const SEAT_Y = 0.5; \/\/ \u5ea7\u9762\u9ad8\u3055\uff08\u5e8a\u304b\u3089\u306e\u8ddd\u96e2\uff09\n    const LEG_D = 0.05;\n    const BACK_H = 0.4;\n    \n    const chairGroup = new THREE.Group();\n    chairGroup.userData.draggable = true;\n    chairGroup.userData.isComposite = true; \/\/ \u8907\u5408\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30d5\u30e9\u30b0\n    \n    \/\/ \u5168\u3066\u306e\u5b50\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306b\u5171\u901a\u306e\u6750\u8cea\u3092\u9069\u7528\n    const material = new THREE.MeshStandardMaterial({ color: color });\n\n    \/\/ 1. \u5ea7\u9762\n    const seatGeometry = new THREE.BoxGeometry(CHAIR_W, SEAT_H, CHAIR_D);\n    const seat = new THREE.Mesh(seatGeometry, material);\n    \/\/ \u5ea7\u9762\u306e\u4e2d\u5fc3\u304cY=SEAT_Y\u306b\u306a\u308b\u3088\u3046\u306b\u914d\u7f6e\n    seat.position.y = SEAT_Y - SEAT_H \/ 2;\n    seat.castShadow = true;\n    seat.receiveShadow = true;\n    chairGroup.add(seat);\n\n    \/\/ 2. \u80cc\u3082\u305f\u308c\n    const backGeometry = new THREE.BoxGeometry(CHAIR_W, BACK_H, 0.05); \/\/ \u5965\u884c\u304d 5cm\n    const back = new THREE.Mesh(backGeometry, material);\n    \/\/ Y\u4f4d\u7f6e: \u5ea7\u9762\u306e\u4e0a\u9762 (SEAT_Y) + \u80cc\u3082\u305f\u308c\u9ad8\u3055\u306e\u534a\u5206 (BACK_H\/2)\n    \/\/ Z\u4f4d\u7f6e: \u6905\u5b50\u306e\u5965\u884c\u304d\u534a\u5206 (CHAIR_D\/2) - \u80cc\u3082\u305f\u308c\u306e\u5965\u884c\u304d\u534a\u5206 (0.05\/2)\n    back.position.set(0, SEAT_Y + BACK_H \/ 2, CHAIR_D \/ 2 - 0.05 \/ 2);\n    back.castShadow = true;\n    back.receiveShadow = true;\n    chairGroup.add(back);\n\n    \/\/ 3. 4\u672c\u306e\u811a\n    const legH = SEAT_Y - SEAT_H; \/\/ \u811a\u306e\u9ad8\u3055\u306f\u5e8a\u304b\u3089\u5ea7\u9762\u306e\u4e0b\u307e\u3067\n    const legGeometry = new THREE.BoxGeometry(LEG_D, legH, LEG_D);\n    \n    function addLeg(lx, lz) {\n        const leg = new THREE.Mesh(legGeometry, material);\n        \/\/ X\/Z\u4f4d\u7f6e: \u6905\u5b50\u306e\u5e45\/\u5965\u884c\u304d\u304b\u3089\u3001\u811a\u306e\u5965\u884c\u304d\/\u5e45\u306e\u534a\u5206\u3092\u5f15\u3044\u305f\u4f4d\u7f6e\n        \/\/ Y\u4f4d\u7f6e: \u811a\u306e\u9ad8\u3055\u306e\u534a\u5206 (legH\/2)\n        leg.position.set(\n            lx * (CHAIR_W \/ 2 - LEG_D \/ 2), \n            legH \/ 2, \n            lz * (CHAIR_D \/ 2 - LEG_D \/ 2)\n        );\n        leg.castShadow = true;\n        leg.receiveShadow = true;\n        chairGroup.add(leg);\n    }\n    \n    addLeg(1, 1);   \/\/ \u53f3\u5965\n    addLeg(1, -1);  \/\/ \u53f3\u524d\n    addLeg(-1, 1);  \/\/ \u5de6\u5965\n    addLeg(-1, -1); \/\/ \u5de6\u524d\n    \n    \/\/ Group\u81ea\u4f53\u306e\u4f4d\u7f6e\u306f\u3001\u30d4\u30dc\u30c3\u30c8\uff08\u539f\u70b9\uff09\u3092\u5e8a(Y=0)\u306b\u8a2d\u5b9a\n    chairGroup.position.set(x, 0, z); \n    \n    chairGroup.userData.id = furniture.length; \n    chairGroup.userData.name = `chair_${chairGroup.userData.id}`;\n    \n    roomGroup.add(chairGroup);\n    furniture.push(chairGroup); \n    \n    return chairGroup;\n}\n\/\/  7. 3D\u30e2\u30c7\u30eb\u30d5\u30a1\u30a4\u30eb(GLTF\/GLB)\u3092\u30ed\u30fc\u30c9\u3057\u30b7\u30fc\u30f3\u306b\u8ffd\u52a0\u3059\u308b\nfunction addLoadSculptedModel(url, x, y , z,rotationY = 0,scale = 1.0) {\n    if (!gltfLoader) {\n        console.error(\"GLTFLoader is not initialized.\");\n        return;\n    }\n    \n    console.log(`Loading model from: ${url}`);\n    \n    gltfLoader.load(\n        url,\n        function (gltf) {\n            const model = gltf.scene;\n            \n            \/\/ \u30e2\u30c7\u30eb\u5168\u4f53\u3092 roomGroup\u306e\u5b50\u3068\u3057\u3066\u914d\u7f6e\u3057\u3001\u30c9\u30e9\u30c3\u30b0\u53ef\u80fd\u306b\u3059\u308b\n            model.position.set(x, y, z); \n            model.rotation.y = rotationY; \/\/\u521d\u671f\u56de\u8ee2\u89d2\u5ea6\u3092\u9069\u7528\n            model.scale.set(scale, scale, scale); \/\/ \u30b9\u30b1\u30fc\u30eb\u3092\u9069\u7528\n            \/\/ \u65e2\u5b58\u306e\u5bb6\u5177\u3068\u540c\u3058\u30d7\u30ed\u30d1\u30c6\u30a3\u3092\u8a2d\u5b9a\n            model.userData.draggable = true;\n            model.userData.id = furniture.length; \n            model.userData.name = `sculpture_${model.userData.id}`;\n            \n            \/\/ \u5f71\u306e\u8a2d\u5b9a\u3068\u30de\u30c6\u30ea\u30a2\u30eb\u306e\u66f4\u65b0\n            model.traverse(function (child) {\n                if (child.isMesh) {\n                    child.castShadow = true;\n                    child.receiveShadow = true;\n                    \/\/ \u30e2\u30c7\u30eb\u306e\u30de\u30c6\u30ea\u30a2\u30eb\u304c\u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u306b\u53cd\u5fdc\u3059\u308b\u3088\u3046\u306b\u8a2d\u5b9a\n                    if (Array.isArray(child.material)) {\n                        child.material.forEach(m =&gt; m.needsUpdate = true);\n                    } else if (child.material) {\n                        child.material.needsUpdate = true;\n                    }\n                }\n            });\n\n            \n            roomGroup.add(model); \n            furniture.push(model);\n        },\n        undefined, \n        \/\/ \u30a8\u30e9\u30fc\u30cf\u30f3\u30c9\u30ea\u30f3\u30b0\n        function (error) {\n            console.error(`An error occurred while loading model: ${url}`, error);\n        }\n    );\n}\n\n\/\/ 8. --- \u30de\u30a6\u30b9\u30a4\u30d9\u30f3\u30c8\u30cf\u30f3\u30c9\u30e9\u30fc ---\n\nfunction updateMouse(event) {\n    const rect = renderer.domElement.getBoundingClientRect();\n    mouse.x = ((event.clientX - rect.left) \/ rect.width) * 2 - 1;\n    mouse.y = -((event.clientY - rect.top) \/ rect.height) * 2 + 1;\n}\n\n\/\/ 9. \u30de\u30a6\u30b9\u30dc\u30bf\u30f3\u304c\u62bc\u3055\u308c\u305f\u3068\u304d (\u30c9\u30e9\u30c3\u30b0\/\u56de\u8ee2\u958b\u59cb)\nfunction onPointerDown(event) {\n    updateMouse(event);\n    raycaster.setFromCamera(mouse, camera);\n    \/\/ Raycasting\u306e\u5bfe\u8c61\u3092roomGroup\u306e\u5b50\u8981\u7d20\u306b\u9650\u5b9a\n    const intersects = raycaster.intersectObjects(roomGroup.children, true);\n\n    if (intersects.length &gt; 0) {\n        let hitObject = intersects[0].object;\n        \n        \/\/ \u8907\u5408\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3001GLTF\u30e2\u30c7\u30eb\u306e\u5b50\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u304c\u30d2\u30c3\u30c8\u3057\u305f\u5834\u5408\u3001\u89aa\uff08Group\/Scene\uff09\u3092\u9078\u629e\n        while (hitObject.parent &amp;&amp; !hitObject.userData.draggable &amp;&amp; hitObject.parent !== roomGroup) {\n            hitObject = hitObject.parent;\n        }\n\n        \/\/ \u8907\u5408\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\uff08THREE.Group\uff09\u306e\u4e00\u90e8\u3067\u3042\u308b\u5834\u5408\u3001\u89aa\u306eGroup\u3092\u9078\u629e\u3059\u308b\n        if (hitObject.parent.userData.isComposite) {\n            selectedObject = hitObject.parent;\n        } else if (hitObject.userData.draggable) { \n            \/\/ \u5358\u7d14\u306aBoxGeometry\uff08\u30c7\u30b9\u30af\u3084\u68da\uff09\u304c\u76f4\u63a5\u5f53\u305f\u3063\u305f\u5834\u5408\n            selectedObject = hitObject;\n        } else {\n            \/\/ \u5f53\u305f\u3063\u305f\u304c\u3001\u30c9\u30e9\u30c3\u30b0\u4e0d\u53ef\uff08\u4f8b\uff1a\u5e8a\uff09\u306e\u5834\u5408\n            selectedObject = null;\n            return;\n        }\n\n        \/\/ selectedObject \u306e Y\u4f4d\u7f6e (\u30d4\u30dc\u30c3\u30c8\u306e\u4f4d\u7f6e) \u3092\u53d6\u5f97\n        const objectY = selectedObject.position.y; \n\n        dragPlane = plane; \/\/ Y=0\u5e73\u9762\n        \/\/ Shift\u30ad\u30fc\u304c\u62bc\u3055\u308c\u3066\u3044\u305f\u3089\u56de\u8ee2\u30e2\u30fc\u30c9\u3001\u305d\u3046\u3067\u306a\u3051\u308c\u3070\u79fb\u52d5\u30e2\u30fc\u30c9\n        if (event.shiftKey) { \n            isRotating = true;\n            isDragging = false; \n\n            \/\/ \u30ea\u30f3\u30b0\u306e\u9ad8\u3055\u3092\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30d4\u30dc\u30c3\u30c8 (Y\u4f4d\u7f6e) \u306b\u8a2d\u5b9a\n            rotationGuide.position.set(selectedObject.position.x, objectY, selectedObject.position.z);\n            rotationGuide.rotation.y = 0; \n            rotationGuide.visible = true;\n            updateExtensionLines(selectedObject, rotationGuide);\n\n        } else {\n            isDragging = true;\n            isRotating = false; \n\n            rotationGuide.visible = false;\n\n            \/\/ \u79fb\u52d5\u30e2\u30fc\u30c9\u306e\u5834\u5408\u306e\u307f\u30aa\u30d5\u30bb\u30c3\u30c8\u3092\u8a08\u7b97\n            if(raycaster.ray.intersectPlane(dragPlane, offset)){\n                isDragging = true;\n            }else{\n                isDragging = false; \n                selectedObject = null;\n            }\n        }\n                \n        controls.enabled = false;\n    } else {\n        \/\/ \u4f55\u3082\u9078\u629e\u3055\u308c\u306a\u304b\u3063\u305f\u5834\u5408\u306f\u3001\u9078\u629e\u3092\u89e3\u9664\u3001\u30ac\u30a4\u30c9\u3092\u975e\u8868\u793a\n        selectedObject = null;\n        isDragging = false;\n        isRotating = false;\n        rotationGuide.visible = false; \n        rotationGuide.children.find(c =&gt; c.userData.isExtension)?.clear();\n        controls.enabled = true;\n    }\n}\n\n\/\/ 10.\u30de\u30a6\u30b9\u304c\u79fb\u52d5\u3057\u305f\u3068\u304d (\u30c9\u30e9\u30c3\u30b0\u4e2d)\nfunction onPointerMove(event) {\n    if (!selectedObject) return;\n\n    updateMouse(event);\n    raycaster.setFromCamera(mouse, camera);\n\n    const objectY = selectedObject.position.y; \n\n    if (isDragging) { \/\/ === \u79fb\u52d5\u30ed\u30b8\u30c3\u30af ===\n        let intersection = new THREE.Vector3();\n        if (raycaster.ray.intersectPlane(plane, intersection)) {\n            \/\/ \u5bb6\u5177: Y=0\u5e73\u9762\u4e0a\u3067\u306e\u79fb\u52d5\n            \/\/ 1. \u73fe\u5728\u306e\u4ea4\u70b9 (intersection) \u3068\u524d\u56de\u306e\u4ea4\u70b9 (offset) \u306e\u5dee\u5206\u3092\u8a08\u7b97\n            const delta = intersection.clone().sub(offset); \/\/ delta = World_Move_Vector\n            \/\/ 2. \u9078\u629e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u73fe\u5728\u306e\u4f4d\u7f6e (\u30ed\u30fc\u30ab\u30eb) \u306b\u5dee\u5206\u3092\u52a0\u3048\u308b\n            selectedObject.position.add(delta);\n            \/\/ 3. Y\u4f4d\u7f6e\u3092\u5143\u306e\u9ad8\u3055\u306b\u56fa\u5b9a\n            selectedObject.position.y = objectY; \n            \/\/ 4. \u6b21\u306e\u30d5\u30ec\u30fc\u30e0\u306e\u305f\u3081\u306b offset \u3092\u73fe\u5728\u306e\u4ea4\u70b9\u306b\u66f4\u65b0\n            offset.copy(intersection);\n\n            if (rotationGuide.visible) {\n                 rotationGuide.position.set(selectedObject.position.x, objectY, selectedObject.position.z);\n            }\n        }\n    } else if (isRotating) { \/\/ === \u56de\u8ee2\u30ed\u30b8\u30c3\u30af (\u56de\u8ee2\u30ac\u30a4\u30c9\u3078\u306e Raycast\u306b\u3088\u308b\u89d2\u5ea6\u6307\u5b9a) ===\n        const guideRing = rotationGuide.children.find(c =&gt; c.type === 'Mesh');\n\n        if (guideRing) {\n            const intersects = raycaster.intersectObject(guideRing, true);\n\n            if (intersects.length &gt; 0) {\n                const intersectionPoint = intersects[0].point;\n                const centerPoint = selectedObject.position.clone();\n                const vector = intersectionPoint.clone().sub(centerPoint);\n                \n                let newAngleRad = Math.atan2(vector.x, vector.z); \n                \n                const snappedAngleDeg = Math.round(THREE.MathUtils.radToDeg(newAngleRad));\n                const finalAngleRad = THREE.MathUtils.degToRad(snappedAngleDeg);\n                selectedObject.rotation.y = finalAngleRad;\n                rotationGuide.position.copy(selectedObject.position);\n                \n                updateExtensionLines(selectedObject, rotationGuide);\n            }\n        }\n    }\n}\n\n\/\/ 11.\u30de\u30a6\u30b9\u30dc\u30bf\u30f3\u304c\u96e2\u3055\u308c\u305f\u3068\u304d (\u7d42\u4e86)\nfunction onPointerUp(event) {\n    if (isDragging || isRotating) { \n        isDragging = false;\n        isRotating = false;\n        selectedObject = null;\n        \/\/ \u30ac\u30a4\u30c9\u3092\u975e\u8868\u793a\u306b\u3059\u308b\n        rotationGuide.visible = false;\n        rotationGuide.children.find(c =&gt; c.userData.isExtension)?.clear();\n        \/\/ \u30ab\u30e1\u30e9\u64cd\u4f5c\u3092\u518d\u6709\u52b9\u5316\n        controls.enabled = true;\n    }\n}\n\n\/\/ 12.\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u73fe\u5728\u306e\u56de\u8ee2\u306b\u5408\u308f\u305b\u3066\u5f15\u304d\u51fa\u3057\u30ac\u30a4\u30c9\u7dda\u3092\u4f5c\u6210\u30fb\u66f4\u65b0\u3059\u308b\nfunction updateExtensionLines(object, guide) {\n    const ringInnerRadius = 2.8; \n    const extensionLinesGroup = guide.children.find(c =&gt; c.userData.isExtension);\n    if (!extensionLinesGroup) return;\n\n    extensionLinesGroup.clear(); \n\n    const lineMaterial = new THREE.LineBasicMaterial({ color: 0xff0000, linewidth: 2 });\n    \n    const rotationMatrix = new THREE.Matrix4().makeRotationY(object.rotation.y);\n    \n    \/\/ 1. Z\u8ef8\u65b9\u5411\u306e\u7dda\n    const startZ = new THREE.Vector3(0, 0, -ringInnerRadius);\n    const endZ = new THREE.Vector3(0, 0, ringInnerRadius);\n    startZ.applyMatrix4(rotationMatrix); \n    endZ.applyMatrix4(rotationMatrix); \n    const pointsZ = [];\n    pointsZ.push(startZ);\n    pointsZ.push(endZ);\n    const geoZ = new THREE.BufferGeometry().setFromPoints(pointsZ);\n    const lineZ = new THREE.Line(geoZ, lineMaterial);\n    \n    \/\/ 2. X\u8ef8\u65b9\u5411\u306e\u7dda \n    const startX = new THREE.Vector3(-ringInnerRadius, 0, 0);\n    const endX = new THREE.Vector3(ringInnerRadius, 0, 0);\n    startX.applyMatrix4(rotationMatrix); \n    endX.applyMatrix4(rotationMatrix); \n    const pointsX = [];\n    pointsX.push(startX);\n    pointsX.push(endX);\n    const geoX = new THREE.BufferGeometry().setFromPoints(pointsX);\n    const lineX = new THREE.Line(geoX, lineMaterial);\n\n    extensionLinesGroup.add(lineZ);\n    extensionLinesGroup.add(lineX);\n}\n\n\/\/ 13.\u56de\u8ee2\u30ac\u30a4\u30c9\uff08\u30ea\u30f3\u30b0\u3068\u76ee\u76db\uff09\u3092\u4f5c\u6210\u3059\u308b \nfunction createRotationGuide() {\n    const guideGroup = new THREE.Group();\n    \n    const innerRadius = 2.8; \n    const outerRadius = 3.3; \n    const segments = 360;    \n    \n    \/\/ 1. \u30ea\u30f3\u30b0\u672c\u4f53 (Raycast\u30bf\u30fc\u30b2\u30c3\u30c8)\n    const ringGeometry = new THREE.RingGeometry(innerRadius, outerRadius, segments, 1, 0, Math.PI * 2);\n    const ringMaterial = new THREE.MeshBasicMaterial({ \n        color: 0xffff00, \n        side: THREE.DoubleSide,\n        transparent: true,\n        opacity: 0.8\n    });\n    const ring = new THREE.Mesh(ringGeometry, ringMaterial);\n    ring.rotation.x = Math.PI \/ 2;\n    ring.position.y = 0.05; \n    guideGroup.add(ring);\n\n    \/\/ 2. 5\u5ea6\u3054\u3068\u306e\u76ee\u76db\u7dda\u3092\u4f5c\u6210\n    const majorLineMaterial = new THREE.LineBasicMaterial({ color: 0x000000, linewidth: 3 }); \n    const minorLineMaterial = new THREE.LineBasicMaterial({ color: 0x000000, linewidth: 1 }); \n    \n    const majorLineVertices = []; \n    const minorLineVertices = []; \n    \n    for (let i = 0; i &lt; 360; i += 5) { \n        const angle = THREE.MathUtils.degToRad(i);\n        \n        let lineLength;\n        let isMajor = false;\n\n        if (i % 90 === 0) { \n            lineLength = 0.4; \n            isMajor = true;\n        } else if (i % 45 === 0) { \n            lineLength = 0.3;\n        } else if (i % 15 === 0) { \n            lineLength = 0.2;\n        } else { \n            lineLength = 0.1;\n        }\n        \n        const currentOuterRadius = outerRadius + lineLength; \n        \n        const targetVertices = isMajor ? majorLineVertices : minorLineVertices;\n\n        targetVertices.push(Math.cos(angle) * innerRadius, 0.06, Math.sin(angle) * innerRadius); \n        targetVertices.push(Math.cos(angle) * currentOuterRadius, 0.06, Math.sin(angle) * currentOuterRadius);\n    }\n    \n    \/\/ \u7d30\u3044\u7dda\u3092\u8ffd\u52a0\n    const minorLineGeometry = new THREE.BufferGeometry();\n    minorLineGeometry.setAttribute('position', new THREE.Float32BufferAttribute(minorLineVertices, 3));\n    const minorLines = new THREE.LineSegments(minorLineGeometry, minorLineMaterial);\n    guideGroup.add(minorLines);\n    \n    \/\/ \u592a\u3044\u7dda\u3092\u8ffd\u52a0\n    const majorLineGeometry = new THREE.BufferGeometry();\n    majorLineGeometry.setAttribute('position', new THREE.Float32BufferAttribute(majorLineVertices, 3));\n    const majorLines = new THREE.LineSegments(majorLineGeometry, majorLineMaterial);\n    guideGroup.add(majorLines);\n\n\n    \/\/ 3. \u5f15\u304d\u51fa\u3057\u7dda\u7528\u306e\u30b0\u30eb\u30fc\u30d7\u3092\u4f5c\u6210\u3057\u8ffd\u52a0\n    const extensionLinesGroup = new THREE.Group();\n    extensionLinesGroup.position.y = 0.07; \n    extensionLinesGroup.userData.isExtension = true;\n    guideGroup.add(extensionLinesGroup); \n\n    guideGroup.userData.isGuide = true; \n    guideGroup.visible = false; \n    roomGroup.add(guideGroup); \/\/ roomGroup\u306b\u8ffd\u52a0\n    \n    return guideGroup;\n}\n\n\/\/ \u5b9f\u884c\ninit();\nanimate();\n\n<\/code><\/pre>\n\n\n<p>UI\u8a2d\u8a08\u306b\u304a\u3044\u3066\u306f\u3001<strong>\u30de\u30a6\u30b9\u30c9\u30e9\u30c3\u30b0\u306b\u3088\u308b\u64cd\u4f5c\u3068\u56de\u8ee2\u3092\u7d44\u307f\u5408\u308f\u305b\u308b<\/strong>\u3053\u3068\u3067\u3001\u30e6\u30fc\u30b6\u30fc\u306f<strong>\u610f\u8b58\u3059\u308b\u3053\u3068\u306a\u304f<\/strong>\u3001\u3088\u308a<strong>\u76f4\u611f\u7684<\/strong>\u306b\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u64cd\u4f5c\u3067\u304d\u308b\u3088\u3046\u306b\u306a\u308a\u3001<strong>\u5229\u4fbf\u6027\u304c\u5411\u4e0a\u3057\u307e\u3059<\/strong>\u3002<\/p>\n\n\n\n<p><img decoding=\"async\" class=\"wp-image-49481\" style=\"width: 640px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-15.png\" alt=\"VS Code\u5b9f\u884c\u7d50\u679c\u30fc\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u56de\u8ee2\"><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u306e\u8a2d\u7f6e\u30fb\u79fb\u52d5\u3068\u4f4d\u7f6e\u60c5\u5831\u306e\u4fdd\u5b58\u6a5f\u80fd\u306e\u8ffd\u52a0<\/h3>\n\n\n\n<p>\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u8a2d\u7f6e\u3068\u79fb\u52d5\u30fb\u56de\u8ee2\u304c\u3072\u3068\u3068\u304a\u308a\u3067\u304d\u307e\u3057\u305f\u306e\u3067\u3001\u6700\u5f8c\u306b\u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u3092\u8a2d\u7f6e\u3057\u3001\u5404\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u5834\u6240\u3092\u4fdd\u5b58\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u307e\u3059\u3002<br>\u203b\u4fdd\u5b58\u306f\u4e00\u6642\u7684\u3067\u30d6\u30e9\u30a6\u30b6\u3092\u7d42\u4e86\u3059\u308b\u3068\u521d\u671f\u5316\u3055\u308c\u307e\u3059\u3002\u7d9a\u3051\u3066\u5229\u7528\u3057\u305f\u3044\u5834\u5408\u306f\u30d5\u30a1\u30a4\u30eb\u3082\u3057\u304f\u306f\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b\u60c5\u5831\u3092\u4fdd\u5b58\u3001\u547c\u3073\u51fa\u3059\u6a5f\u80fd\u3092\u5225\u9014\u8ffd\u52a0\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002<br>index.html\u306f\u65e2\u306b\u300c\u4fdd\u5b58\u300d\u300c\u623b\u3059\u300d\u30dc\u30bf\u30f3\u3092\u914d\u7f6e\u6e08\u307f\u3067\u3059\u3002\u3053\u306e\u30dc\u30bf\u30f3\u30a2\u30af\u30b7\u30e7\u30f3\u306e\u51e6\u7406\u3092\u8ffd\u52a0\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<div class=\"wp-block-luxe-blocks-topic\" style=\"margin-top:10px;margin-bottom:30px\"><div class=\"wp-block-luxe-blocks-topic-title\" style=\"color:#fff;background-color:#006edc;border:1px solid #006edc;padding:2px 14px;align-items:center\">main.js \u8ffd\u52a0\u5185\u5bb9<\/div><div class=\"wp-block-luxe-blocks-topic-content\" style=\"border:1px solid #006edc;padding:0px 15px 0px 15px\">\n\n<ul type=\"1\">\n\n<li>\/\/ === 1-5. \u30e9\u30a4\u30c8 (Light) \u306e\u8ffd\u52a0 ===\n\n<ul>\n\n<li>\u65e2\u5b58\u306e\u6307\u5411\u6027\u30e9\u30a4\u30c8\u3092\u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\uff08THREE.SpotLight\uff09\u306b\u7f6e\u304d\u63db\u3048\u307e\u3059\u3002<\/li>\n\n\n<li>THREE.SpotLight()\u3067\u8ffd\u52a0\u3057\u307e\u3059\u3002\u3053\u308c\u3067\u5e8a\u306b\u5f71\u304c\u843d\u3061\u308b\u3088\u3046\u306b\u306a\u308a\u307e\u3059\u3002<\/li>\n\n\n<li>THREE.SphereGeometry\u3092\u4f7f\u3063\u3066\u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u306e\u4f4d\u7f6e\u306b\u7403\u4f53\u3092\u8a2d\u7f6e\u3057\u307e\u3059\u3002\u4efb\u610f\u306e\u4f4d\u7f6e\u304b\u3089\u5149\u6e90\u306e\u52b9\u679c\u3092\u78ba\u8a8d\u3059\u308b\u305f\u3081\u306b\u30c9\u30e9\u30c3\u30b0\u64cd\u4f5c\u306e\u5bfe\u8c61\u3068\u3057\u307e\u3059\u3002<\/li>\n\n\n<li>\u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u306e\u30bf\u30fc\u30b2\u30c3\u30c8\u306f\u5e8a\u306e\u4e2d\u592e\u306b\u56fa\u5b9a\u3057\u307e\u3059\u3002<\/li>\n\n<\/ul>\n\n<\/li>\n\n\n<li>\u30de\u30a6\u30b9\u30a4\u30d9\u30f3\u30c8\u95a2\u6570\u306e\u4fee\u6b63<br>onPointerMove\u3001onPointerDown\u3092\u6539\u9020\u3057\u307e\u3059\u3002\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u306e\u5909\u66f4\u7b87\u6240\u3092\u53c2\u8003\u306b\u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/li>\n\n\n<li>\u5bb6\u5177\u306a\u3069\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u72b6\u614b\u3092\u8ffd\u8de1\u3057\u3001localStorage \u3092\u4f7f\u3063\u3066\u72b6\u614b\u306e\u4fdd\u5b58\u3068\u623b\u3059\u3092\u884c\u3046\u30ed\u30b8\u30c3\u30af\u3092\u5b9f\u88c5\u3057\u307e\u3059\u3002\n\n<ul>\n\n<li>getFurnitureState() \uff1a\u73fe\u5728\u306e\u5bb6\u5177\u3001\u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u3001\u30ab\u30e1\u30e9\u306e\u72b6\u614b\u3092\u53ce\u96c6\u3059\u308b<\/li>\n\n\n<li>setFurnitureState()\uff1a\u4fdd\u5b58\u3055\u308c\u305f\u72b6\u614b\u3092\u5bb6\u5177\u3001\u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u3001<\/li>\n\n\n<li>saveState()\uff1a\u73fe\u5728\u306e\u72b6\u614b\u3092 localStorage \u306b\u4fdd\u5b58\u3059\u308b.<\/li>\n\n\n<li>loadState()\uff1alocalStorage \u304b\u3089\u72b6\u614b\u3092\u8aad\u307f\u8fbc\u3080<\/li>\n\n<\/ul>\n\n<\/li>\n\n\n<li>\u4fdd\u5b58\/\u623b\u3059\u30dc\u30bf\u30f3\u306e\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u30fc\u3092\u8ffd\u52a0\u3057\u307e\u3059\u3002<\/li>\n\n<\/ul>\n\n<\/div><\/div>\n\n\n<pre class=\"line-numbers highlight-code-spotlight\"><code class=\"language-javascript\">\/\/ main.js\n\/\/ [main-007-spotlight] \u5b8c\u6210\u7248\n\/\/ index.html \u306e importmap \u306e\u8a2d\u5b9a\u306b\u57fa\u3065\u304d\u3001\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\u3092\u30a4\u30f3\u30dd\u30fc\u30c8\nimport * as THREE from \"three\";\nimport { OrbitControls } from '.\/jsm\/controls\/OrbitControls.js';\nimport { GLTFLoader } from '.\/jsm\/loaders\/GLTFLoader.js';\n\/\/ \u5fc5\u8981\u306a\u5909\u6570\u3092\u30b0\u30ed\u30fc\u30d0\u30eb\u30b9\u30b3\u30fc\u30d7\u3067\u5b9a\u7fa9\nlet scene, camera, renderer, controls;\nlet roomGroup; \/\/ \u5e8a\u3001\u58c1\u3001\u5bb6\u5177\u3092\u307e\u3068\u3081\u308b\u30b0\u30eb\u30fc\u30d7\nlet gltfLoader; \/\/ GLTF\u30ed\u30fc\u30c0\u30fc\nconst roomSize = 10; \/\/ \u90e8\u5c4b\u306e\u30b5\u30a4\u30ba (10m x 10m)\nconst furniture = []; \/\/ \u8907\u6570\u306e\u5bb6\u5177\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u9806\u5e8f\u4ed8\u3051\u3057\u3066\u4fdd\u7ba1\n\/\/ --- \u30c9\u30e9\u30c3\u30b0&amp;\u30c9\u30ed\u30c3\u30d7\u306b\u5fc5\u8981\u306a\u5909\u6570 ---\nlet raycaster;\nlet mouse;\nlet isDragging = false; \/\/ \u79fb\u52d5\u4e2d\u30d5\u30e9\u30b0\nlet selectedObject = null;\nlet plane;\nlet offset = new THREE.Vector3();\n\/\/ --- \u56de\u8ee2\u306b\u5fc5\u8981\u306a\u5909\u6570 ---\nlet dragPlane;\nlet isRotating = false; \nlet rotationGuide = null;\n\/\/ --- \u30e9\u30a4\u30c8\u5236\u5fa1\u7528\u306e\u5909\u6570 ---\nlet spotLight;\nlet spotLightControlMesh; \/\/ \u30aa\u30ec\u30f3\u30b8\u8272\u306e\u7403\u4f53 (\u4f4d\u7f6e)\nlet spotLightTargetControlMesh; \/\/ \u9752\u8272\u306e\u7403\u4f53 (\u30bf\u30fc\u30b2\u30c3\u30c8)\n\/\/ 1. \u521d\u671f\u5316\u95a2\u6570\uff1a3D\u4e16\u754c\u306e\u571f\u53f0\u3092\u4f5c\u308b\nfunction init() {\n    \/\/=== 1-1. \u30b7\u30fc\u30f3 (Scene) \u306e\u4f5c\u6210 ===\n    scene = new THREE.Scene();\n    scene.background = new THREE.Color(0xf0f0f0);  \/\/ \u80cc\u666f\u8272\u3092\u8584\u3044\u30b0\u30ec\u30fc\u306b\u8a2d\u5b9a\n    roomGroup = new THREE.Group();\n    scene.add(roomGroup);\n    \/\/ \u5ea7\u6a19\u8ef8\u30d8\u30eb\u30d1\u30fc\u3092\u8ffd\u52a0\uff08X\u8ef8\uff1a\u8d64\u3001Y\u8ef8\uff1a\u7dd1\u3001Z\u8ef8\uff1a\u9752\uff09\n    const axesHelper = new THREE.AxesHelper(10); \/\/ \u30b5\u30a4\u30ba10\n    scene.add(axesHelper);\n\n    \/\/ === 1-2. \u30ab\u30e1\u30e9 (Camera) \u306e\u8a2d\u5b9a ===\n    const fov = 75; \/\/ \u8996\u91ce\u89d2 (Field of View)\n    const aspect = window.innerWidth \/ window.innerHeight;  \/\/ \u30a2\u30b9\u30da\u30af\u30c8\u6bd4\n    const near = 0.1; \/\/ \u63cf\u753b\u958b\u59cb\u8ddd\u96e2\n    const far = 1000; \/\/ \u63cf\u753b\u7d42\u4e86\u8ddd\u96e2\n    camera = new THREE.PerspectiveCamera(fov, aspect, near, far);\n    \/\/ \u30ab\u30e1\u30e9\u306e\u521d\u671f\u4f4d\u7f6e\u3092\u6c7a\u5b9a (X, Y, Z)\n    camera.position.set(10, 15, 15);\n    camera.lookAt(0, 0, 0); \/\/ \u539f\u70b9(0, 0, 0)\u3092\u898b\u308b\u3088\u3046\u306b\u8a2d\u5b9a\n\n    \/\/ === 1-3. \u30ec\u30f3\u30c0\u30e9\u30fc (Renderer) \u306e\u4f5c\u6210 ===\n    renderer = new THREE.WebGLRenderer({ antialias: true }); \/\/ \u30a2\u30f3\u30c1\u30a8\u30a4\u30ea\u30a2\u30b9\u3067\u63cf\u753b\u3092\u6ed1\u3089\u304b\u306b\n    renderer.setSize(window.innerWidth, window.innerHeight); \/\/ \u63cf\u753b\u30b5\u30a4\u30ba\u3092\u30a6\u30a3\u30f3\u30c9\u30a6\u30b5\u30a4\u30ba\u306b\u5408\u308f\u305b\u308b\n    \n    renderer.outputEncoding = THREE.sRGBEncoding; \/\/ \u30ec\u30f3\u30c0\u30ea\u30f3\u30b0\u54c1\u8cea\u6539\u5584\n    renderer.shadowMap.enabled = true; \/\/ \u5f71\u306e\u63cf\u753b\u3092\u6709\u52b9\u5316\n    \/\/ GLTF\u30ed\u30fc\u30c0\u30fc\u306e\u521d\u671f\u5316\n    gltfLoader = new GLTFLoader();\n\n    \/\/ \u751f\u6210\u3055\u308c\u305f&lt;canvas&gt;\u8981\u7d20\u3092HTML&lt;body&gt;\u306b\u8ffd\u52a0\n    document.body.appendChild(renderer.domElement);\n\n    \/\/ === 1-4. \u30ab\u30e1\u30e9\u64cd\u4f5c (OrbitControls) \u306e\u8a2d\u5b9a ===\n    \/\/ \u30a4\u30f3\u30dd\u30fc\u30c8\u3057\u305f OrbitControls \u3092\u4f7f\u3063\u3066\u3001\u30de\u30a6\u30b9\u3067\u30ab\u30e1\u30e9\u3092\u52d5\u304b\u305b\u308b\u3088\u3046\u306b\u3059\u308b\n    controls = new OrbitControls(camera, renderer.domElement);\n    controls.enableDamping = true;  \/\/ \u52d5\u304d\u3092\u6ed1\u3089\u304b\u306b\u3059\u308b\n    controls.dampingFactor = 0.05;\n\n    \/\/ === 1-5. \u30e9\u30a4\u30c8 (Light) \u306e\u8ffd\u52a0 ===\n    \/\/ \u90e8\u5c4b\u5168\u4f53\u3092\u5747\u7b49\u306b\u7167\u3089\u3059\u74b0\u5883\u5149\n    const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); \/\/ \u5f31\u3081\u306e\u5149\n    scene.add(ambientLight);\n    \/\/ \u7279\u5b9a\u306e\u65b9\u5411\u304b\u3089\u7167\u3089\u3059\u6307\u5411\u6027\u5149\uff08\u5f71\u3092\u843d\u3068\u3059\u305f\u3081\u306b\u5fc5\u8981\uff09\n    \/\/const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);\n    \/\/directionalLight.position.set(20, 30, 10);\n    \/\/scene.add(directionalLight);\n    \/\/ \u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u306e\u8a2d\u5b9a\u3092\u66f4\u65b0(\u5e8a\u306b\u3082\u5f71\u304c\u843d\u3061\u308b)\n    spotLight = new THREE.SpotLight(0xffffff, 5.0); \n    spotLight.position.set(0, 7, 0);\n    spotLight.angle = Math.PI \/ 4;\n    spotLight.penumbra = 0.2; \n    spotLight.decay = 0.5; \n    spotLight.distance = 20; \n    spotLight.castShadow = true;\n    spotLight.shadow.mapSize.width = 1024;\n    spotLight.shadow.mapSize.height = 1024;\n    spotLight.shadow.camera.near = 0.1;\n    spotLight.shadow.camera.far = 10; \n    scene.add(spotLight)\n    const meshSize = 0.4; \n    const meshGeometry = new THREE.SphereGeometry(meshSize \/ 2, 16, 16);\n    \n    \/\/ 1. \u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u4f4d\u7f6e\u5236\u5fa1\u30e1\u30c3\u30b7\u30e5 (\u30aa\u30ec\u30f3\u30b8\u8272\u306e\u7403\u4f53)\n    const meshMaterial = new THREE.MeshBasicMaterial({ \n        color: 0xffa500,\n        transparent: true,\n        opacity: 0.8\n    });\n    spotLightControlMesh = new THREE.Mesh(meshGeometry, meshMaterial);\n    spotLightControlMesh.position.copy(spotLight.position); \n    spotLightControlMesh.userData.draggable = true;\n    spotLightControlMesh.userData.isLightControl = true; \/\/ \u30e9\u30a4\u30c8\u4f4d\u7f6e\u5236\u5fa1\u7528\u30d5\u30e9\u30b0\n    spotLightControlMesh.userData.name = `light_control`;\n    roomGroup.add(spotLightControlMesh); \n    \n    \/\/ 2. \u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u30bf\u30fc\u30b2\u30c3\u30c8\u5236\u5fa1\u30e1\u30c3\u30b7\u30e5 (\u9752\u8272\u306e\u7403\u4f53)\n    const targetMeshMaterial = new THREE.MeshBasicMaterial({ \n        color: 0x0000ff,\n        transparent: true,\n        opacity: 0.8\n    });\n    spotLightTargetControlMesh = new THREE.Mesh(meshGeometry, targetMeshMaterial); \/\/ \u2605\u30b5\u30a4\u30ba\u306f\u7d71\u4e00\n    spotLightTargetControlMesh.position.set(0, 0.05, 0); \n    spotLightTargetControlMesh.userData.draggable = true;\n    spotLightTargetControlMesh.userData.isLightTargetControl = true; \/\/ \u30e9\u30a4\u30c8\u30bf\u30fc\u30b2\u30c3\u30c8\u5236\u5fa1\u7528\u30d5\u30e9\u30b0\n    spotLightTargetControlMesh.userData.name = `light_target_control`;\n    roomGroup.add(spotLightTargetControlMesh); \n    \n    \/\/ SpotLight\u306e\u30bf\u30fc\u30b2\u30c3\u30c8\u3092\u5236\u5fa1\u30e1\u30c3\u30b7\u30e5\u306e\u30ef\u30fc\u30eb\u30c9\u4f4d\u7f6e\u306b\u540c\u671f\u3055\u305b\u308b\n    spotLight.target.position.set(0, 0.05, 0);\n    scene.add(spotLight.target);\n\n    \/\/ === 1-6 &amp; 1-7. \u90e8\u5c4b\u306e\u69cb\u9020\uff08\u5e8a\u3068\u58c1\uff09\u3068\u30b0\u30ea\u30c3\u30c9\u5b9a\u898f\u306e\u4f5c\u6210 ===\n    createRoomStructure();\n\n    \/\/ === 1-8. \u5bb6\u5177\uff08\u30d7\u30ec\u30fc\u30b9\u30db\u30eb\u30c0\u30fc\uff09\u306e\u4f5c\u6210\u3068\u914d\u7f6e ===\n    \/\/ \u5bb6\u5177\u306e\u914d\u7f6e\u4f8b\n    const deskHeight = 0.75;\n    const chairHeight = 0.5;\n    addFurniture(2, 2, 1, 3, 2.0, 0xa0522d); \/\/ \u68da\n    addFurniture(-3, -3, 3, 1.5, deskHeight, 0xdeb887); \/\/ \u30c7\u30b9\u30af\n    \/\/addFurniture(-3, -1, 0.5, 0.5, chairHeight, 0x800000); \/\/ \u30c1\u30a7\u30a2\n    addChair(-3, -1, 0x800000); \/\/ \u30c1\u30a7\u30a2\n\n    \/\/ \u30b9\u30ab\u30eb\u30d7\u30c8\u30e2\u30c7\u30eb(\u9f8d)\u306e\u30ed\u30fc\u30c9\u3068\u914d\u7f6e\n    addLoadSculptedModel('.\/dragon-3d-model-2.glb',-3, 1.3,-2.8,Math.PI \/ 2,2.0);\n\n    \/\/ === 1-9. \u30c9\u30e9\u30c3\u30b0\uff06\u30c9\u30ed\u30c3\u30d7\u6a5f\u80fd\u306e\u521d\u671f\u5316 ===\n    raycaster = new THREE.Raycaster();\n    mouse = new THREE.Vector2();\n    plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0); \n    dragPlane = plane; \n    \/\/ === 1-10. \u56de\u8ee2\u30ac\u30a4\u30c9\u30ea\u30f3\u30b0\u306e\u521d\u671f\u5316 ===\n    rotationGuide = createRotationGuide(); \n    \/\/ \u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u30fc\n    renderer.domElement.addEventListener('pointerdown', onPointerDown, false);\n    renderer.domElement.addEventListener('pointermove', onPointerMove, false);\n    renderer.domElement.addEventListener('pointerup', onPointerUp, false);\n    \n    window.addEventListener('resize', onWindowResize, false);\n    \/\/ \u4fdd\u5b58\/\u623b\u3059\u30dc\u30bf\u30f3\u306e\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u30fc\n    document.getElementById('saveButton').addEventListener('click', saveState);\n    document.getElementById('loadButton').addEventListener('click', loadState);\n}\n\/\/ 2. \u63cf\u753b\u30eb\u30fc\u30d7\u95a2\u6570\uff1a\u30a2\u30cb\u30e1\u30fc\u30b7\u30e7\u30f3\u306e\u5fc3\u81d3\u90e8\nfunction animate() {\n    requestAnimationFrame(animate); \/\/ \u30d6\u30e9\u30a6\u30b6\u306e\u518d\u63cf\u753b\u30bf\u30a4\u30df\u30f3\u30b0\u306b\u5408\u308f\u305b\u3066\u30eb\u30fc\u30d7\u3092\u7d99\u7d9a\n    controls.update();\/\/ \u30ab\u30e1\u30e9\u64cd\u4f5c\u306e\u30c0\u30f3\u30d4\u30f3\u30b0\u52b9\u679c\u3092\u9069\u7528\u3059\u308b\u305f\u3081\u306b\u66f4\u65b0\u304c\u5fc5\u8981\n    \/\/ \u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u306e\u30bf\u30fc\u30b2\u30c3\u30c8\u4f4d\u7f6e\u3092\u5236\u5fa1\u30e1\u30c3\u30b7\u30e5\u306e\u30ef\u30fc\u30eb\u30c9\u4f4d\u7f6e\u306b\u540c\u671f\n    if (spotLightTargetControlMesh) {\n        \/\/ roomGroup\u306e\u5b50\u8981\u7d20\u3068\u3057\u3066\u52d5\u304b\u3057\u3066\u3044\u308b\u306e\u3067\u3001\u305d\u306e\u30ef\u30fc\u30eb\u30c9\u4f4d\u7f6e\u3092\u53d6\u5f97\n        spotLightTargetControlMesh.updateWorldMatrix(true, false);\n        spotLight.target.position.setFromMatrixPosition(spotLightTargetControlMesh.matrixWorld);\n    }\n    renderer.render(scene, camera); \/\/ \u30b7\u30fc\u30f3\u3092\u30ab\u30e1\u30e9\u306e\u8996\u70b9\u304b\u3089\u63cf\u753b \n}\n\/\/ 3. \u30a6\u30a3\u30f3\u30c9\u30a6\u30ea\u30b5\u30a4\u30ba\u51e6\u7406\nfunction onWindowResize() {\n    camera.aspect = window.innerWidth \/ window.innerHeight;    \/\/ \u30ab\u30e1\u30e9\u306e\u30a2\u30b9\u30da\u30af\u30c8\u6bd4\u66f4\u65b0\n    camera.updateProjectionMatrix(); \/\/ \u30ab\u30e1\u30e9\u306e\u6295\u5f71\u884c\u5217\u3092\u66f4\u65b0\n    renderer.setSize(window.innerWidth, window.innerHeight); \/\/ \u30ec\u30f3\u30c0\u30e9\u30fc\u306e\u30b5\u30a4\u30ba\u66f4\u65b0\n}\n\/\/ 4.\u90e8\u5c4b\u5168\u4f53\u69cb\u9020\u306e\u4f5c\u6210\nfunction createRoomStructure() {\n    const wallHeight = 2; \n    \/\/ \u5e8a\u306e\u4f5c\u6210\n    const floorGeometry = new THREE.PlaneGeometry(roomSize, roomSize); \n    const floorMaterial = new THREE.MeshStandardMaterial({ \n        color: 0xf8feff,\n        side: THREE.DoubleSide\n    });\n    const floor = new THREE.Mesh(floorGeometry, floorMaterial);\n    floor.rotation.x = Math.PI \/ 2;\n    floor.position.y = 0; \n    floor.receiveShadow = true; \n    roomGroup.add(floor); \n    \n    \/\/ \u8996\u899a\u7684\u5b9a\u898f\uff08GridHelper\uff09\u306e\u8ffd\u52a0 (1m\u9593\u9694)\n    const gridHelper = new THREE.GridHelper(\n        roomSize, roomSize, 0x444444, 0x888888        \n    );\n    gridHelper.position.y = 0.01; \n    roomGroup.add(gridHelper); \n    \/\/ \u58c1\u306e\u534a\u900f\u660e\u30de\u30c6\u30ea\u30a2\u30eb\u3092\u4f5c\u6210 \n    const wallMaterial = new THREE.MeshStandardMaterial({ \n        color: 0xf0e68c, \n        transparent: true, \n        opacity: 0.3,      \n        side: THREE.DoubleSide \n    });\n    \n    \/\/ \u58c1\u306e\u4f5c\u6210\u30d8\u30eb\u30d1\u30fc\n    function createWall(x, z, length, height, rotationY) {\n        const wallGeometry = new THREE.BoxGeometry(length, height, 0.1); \n        const wall = new THREE.Mesh(wallGeometry, wallMaterial); \n        \n        wall.position.y = height \/ 2;\n        wall.position.x = x;\n        wall.position.z = z;\n        wall.rotation.y = rotationY;\n        wall.receiveShadow = true;\n        roomGroup.add(wall); \n    }\n    \n    \/\/ 4\u3064\u306e\u58c1\u3092\u4f5c\u6210\n    createWall(0, -roomSize \/ 2, roomSize, wallHeight, 0); \n    createWall(0, roomSize \/ 2, roomSize, wallHeight, 0); \n    createWall(-roomSize \/ 2, 0, roomSize, wallHeight, Math.PI \/ 2); \n    createWall(roomSize \/ 2, 0, roomSize, wallHeight, Math.PI \/ 2);  \n}\n\/\/ 5.\u5358\u7d14\u306a\u5bb6\u5177\uff08BoxGeometry\uff09\u3092\u8ffd\u52a0\u3059\u308b\nfunction addFurniture(x, z, width, depth, height, color) {\n    \/\/ BoxGeometry: \u7acb\u65b9\u4f53\/\u76f4\u65b9\u4f53\u306e\u5f62\u72b6\n    const geometry = new THREE.BoxGeometry(width, height, depth); \n    const material = new THREE.MeshStandardMaterial({ color: color });\n    const mesh = new THREE.Mesh(geometry, material);\n    \n    mesh.position.set(x, height \/ 2, z);\n    mesh.castShadow = true; \n    mesh.receiveShadow = true;\n    \/\/ \u5f8c\u3067\u4fdd\u5b58\u30fb\u5143\u306e\u4f4d\u7f6e\u306b\u623b\u3059\u6642\u306b\u4e00\u8cab\u6027\u3092\u4fdd\u3064ID\u3092\u8a2d\u5b9a\u3057\u3066\u304a\u304f\n    mesh.userData.draggable = true;\n    mesh.userData.id = furniture.length; \n    mesh.userData.name = `furniture_${mesh.userData.id}`;\n    roomGroup.add(mesh); \/\/ roomGroup\u306b\u8ffd\u52a0\n    furniture.push(mesh); \/\/ \u5bb6\u5177\u306e\u4f4d\u7f6e\u72b6\u614b\u3092\u4fdd\u7ba1\n\n    return mesh;\n}\n\/\/ 6.\u8907\u5408\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\uff08\u6905\u5b50\uff09\u3092\u8ffd\u52a0\u3059\u308b\u3002\u8907\u6570\u306eMesh\u3092THREE.Group\u306b\u307e\u3068\u3081\u307e\u3059\u3002\nfunction addChair(x, z, color) {\n    const CHAIR_W = 0.5;\n    const CHAIR_D = 0.5;\n    const SEAT_H = 0.05;\n    const SEAT_Y = 0.5; \/\/ \u5ea7\u9762\u9ad8\u3055\uff08\u5e8a\u304b\u3089\u306e\u8ddd\u96e2\uff09\n    const LEG_D = 0.05;\n    const BACK_H = 0.4;\n    \n    const chairGroup = new THREE.Group();\n    chairGroup.userData.draggable = true;\n    chairGroup.userData.isComposite = true; \/\/ \u8907\u5408\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30d5\u30e9\u30b0\n    \n    \/\/ \u5168\u3066\u306e\u5b50\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306b\u5171\u901a\u306e\u6750\u8cea\u3092\u9069\u7528\n    const material = new THREE.MeshStandardMaterial({ color: color });\n    \/\/ 1. \u5ea7\u9762\n    const seatGeometry = new THREE.BoxGeometry(CHAIR_W, SEAT_H, CHAIR_D);\n    const seat = new THREE.Mesh(seatGeometry, material);\n    \/\/ \u5ea7\u9762\u306e\u4e2d\u5fc3\u304cY=SEAT_Y\u306b\u306a\u308b\u3088\u3046\u306b\u914d\u7f6e\n    seat.position.y = SEAT_Y - SEAT_H \/ 2;\n    seat.castShadow = true;\n    seat.receiveShadow = true;\n    chairGroup.add(seat);\n    \/\/ 2. \u80cc\u3082\u305f\u308c\n    const backGeometry = new THREE.BoxGeometry(CHAIR_W, BACK_H, 0.05); \/\/ \u5965\u884c\u304d 5cm\n    const back = new THREE.Mesh(backGeometry, material);\n    \/\/ Y\u4f4d\u7f6e: \u5ea7\u9762\u306e\u4e0a\u9762 (SEAT_Y) + \u80cc\u3082\u305f\u308c\u9ad8\u3055\u306e\u534a\u5206 (BACK_H\/2)\n    \/\/ Z\u4f4d\u7f6e: \u6905\u5b50\u306e\u5965\u884c\u304d\u534a\u5206 (CHAIR_D\/2) - \u80cc\u3082\u305f\u308c\u306e\u5965\u884c\u304d\u534a\u5206 (0.05\/2)\n    back.position.set(0, SEAT_Y + BACK_H \/ 2, CHAIR_D \/ 2 - 0.05 \/ 2);\n    back.castShadow = true;\n    back.receiveShadow = true;\n    chairGroup.add(back);\n    \/\/ 3. 4\u672c\u306e\u811a\n    const legH = SEAT_Y - SEAT_H; \/\/ \u811a\u306e\u9ad8\u3055\u306f\u5e8a\u304b\u3089\u5ea7\u9762\u306e\u4e0b\u307e\u3067\n    const legGeometry = new THREE.BoxGeometry(LEG_D, legH, LEG_D);\n    \n    function addLeg(lx, lz) {\n        const leg = new THREE.Mesh(legGeometry, material);\n        \/\/ X\/Z\u4f4d\u7f6e: \u6905\u5b50\u306e\u5e45\/\u5965\u884c\u304d\u304b\u3089\u3001\u811a\u306e\u5965\u884c\u304d\/\u5e45\u306e\u534a\u5206\u3092\u5f15\u3044\u305f\u4f4d\u7f6e\n        \/\/ Y\u4f4d\u7f6e: \u811a\u306e\u9ad8\u3055\u306e\u534a\u5206 (legH\/2)\n        leg.position.set(\n            lx * (CHAIR_W \/ 2 - LEG_D \/ 2), \n            legH \/ 2, \n            lz * (CHAIR_D \/ 2 - LEG_D \/ 2)\n        );\n        leg.castShadow = true;\n        leg.receiveShadow = true;\n        chairGroup.add(leg);\n    }\n    \n    addLeg(1, 1);   \/\/ \u53f3\u5965\n    addLeg(1, -1);  \/\/ \u53f3\u524d\n    addLeg(-1, 1);  \/\/ \u5de6\u5965\n    addLeg(-1, -1); \/\/ \u5de6\u524d\n    \n    \/\/ Group\u81ea\u4f53\u306e\u4f4d\u7f6e\u306f\u3001\u30d4\u30dc\u30c3\u30c8\uff08\u539f\u70b9\uff09\u3092\u5e8a(Y=0)\u306b\u8a2d\u5b9a\n    chairGroup.position.set(x, 0, z); \n    \n    chairGroup.userData.id = furniture.length; \n    chairGroup.userData.name = `chair_${chairGroup.userData.id}`;\n    \n    roomGroup.add(chairGroup);\n    furniture.push(chairGroup); \n    \n    return chairGroup;\n}\n\/\/  7. 3D\u30e2\u30c7\u30eb\u30d5\u30a1\u30a4\u30eb(GLTF\/GLB)\u3092\u30ed\u30fc\u30c9\u3057\u30b7\u30fc\u30f3\u306b\u8ffd\u52a0\u3059\u308b\nfunction addLoadSculptedModel(url, x, y , z,rotationY = 0,scale = 1.0) {\n    if (!gltfLoader) {\n        console.error(\"GLTFLoader is not initialized.\");\n        return;\n    }\n    \n    console.log(`Loading model from: ${url}`);\n    \n    gltfLoader.load(\n        url,\n        function (gltf) {\n            const model = gltf.scene;\n            \n            \/\/ \u30e2\u30c7\u30eb\u5168\u4f53\u3092 roomGroup\u306e\u5b50\u3068\u3057\u3066\u914d\u7f6e\u3057\u3001\u30c9\u30e9\u30c3\u30b0\u53ef\u80fd\u306b\u3059\u308b\n            model.position.set(x, y, z); \n            model.rotation.y = rotationY; \/\/\u521d\u671f\u56de\u8ee2\u89d2\u5ea6\u3092\u9069\u7528\n            model.scale.set(scale, scale, scale); \/\/ \u30b9\u30b1\u30fc\u30eb\u3092\u9069\u7528\n            \/\/ \u65e2\u5b58\u306e\u5bb6\u5177\u3068\u540c\u3058\u30d7\u30ed\u30d1\u30c6\u30a3\u3092\u8a2d\u5b9a\n            model.userData.draggable = true;\n            model.userData.id = furniture.length; \n            model.userData.name = `sculpture_${model.userData.id}`;\n            \n            \/\/ \u5f71\u306e\u8a2d\u5b9a\u3068\u30de\u30c6\u30ea\u30a2\u30eb\u306e\u66f4\u65b0\n            model.traverse(function (child) {\n                if (child.isMesh) {\n                    child.castShadow = true;\n                    child.receiveShadow = true;\n                    \/\/ \u30e2\u30c7\u30eb\u306e\u30de\u30c6\u30ea\u30a2\u30eb\u304c\u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u306b\u53cd\u5fdc\u3059\u308b\u3088\u3046\u306b\u8a2d\u5b9a\n                    if (Array.isArray(child.material)) {\n                        child.material.forEach(m =&gt; m.needsUpdate = true);\n                    } else if (child.material) {\n                        child.material.needsUpdate = true;\n                    }\n                }\n            });\n            \n            roomGroup.add(model); \n            furniture.push(model);\n        },\n        undefined, \n        \/\/ \u30a8\u30e9\u30fc\u30cf\u30f3\u30c9\u30ea\u30f3\u30b0\n        function (error) {\n            console.error(`An error occurred while loading model: ${url}`, error);\n            \/\/showCustomDialog(`3D\u30e2\u30c7\u30eb\u300c${url}\u300d\u306e\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002`, true);\n        }\n    );\n}\n\/\/ 8. --- \u30de\u30a6\u30b9\u30a4\u30d9\u30f3\u30c8\u30cf\u30f3\u30c9\u30e9\u30fc ---\nfunction updateMouse(event) {\n    const rect = renderer.domElement.getBoundingClientRect();\n    mouse.x = ((event.clientX - rect.left) \/ rect.width) * 2 - 1;\n    mouse.y = -((event.clientY - rect.top) \/ rect.height) * 2 + 1;\n}\n\/\/ 9. \u30de\u30a6\u30b9\u30dc\u30bf\u30f3\u304c\u62bc\u3055\u308c\u305f\u3068\u304d (\u30c9\u30e9\u30c3\u30b0\/\u56de\u8ee2\u958b\u59cb)\nfunction onPointerDown(event) {\n    updateMouse(event);\n    raycaster.setFromCamera(mouse, camera);\n    \/\/ Raycasting\u306e\u5bfe\u8c61\u3092roomGroup\u306e\u5b50\u8981\u7d20\u306b\u9650\u5b9a\n    const intersects = raycaster.intersectObjects(roomGroup.children, true);\n    if (intersects.length &gt; 0) {\n        let hitObject = intersects[0].object;\n        \/\/ \u8907\u5408\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3001GLTF\u30e2\u30c7\u30eb\u306e\u5b50\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u304c\u30d2\u30c3\u30c8\u3057\u305f\u5834\u5408\u3001\u89aa\uff08Group\/Scene\uff09\u3092\u9078\u629e\n        while (hitObject.parent &amp;&amp; !hitObject.userData.draggable &amp;&amp; hitObject.parent !== roomGroup) {\n            hitObject = hitObject.parent;\n        }\n        \n        \/\/ \u8907\u5408\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\uff08THREE.Group\uff09\u306e\u4e00\u90e8\u3067\u3042\u308b\u5834\u5408\u3001\u89aa\u306eGroup\u3092\u9078\u629e\u3059\u308b\n        if (hitObject.parent.userData.isComposite) {\n            selectedObject = hitObject.parent;\n        } else if (hitObject.userData.draggable) { \n            \/\/ \u5358\u7d14\u306aBoxGeometry\uff08\u30c7\u30b9\u30af\u3084\u68da\uff09\u304c\u76f4\u63a5\u5f53\u305f\u3063\u305f\u5834\u5408\n            selectedObject = hitObject;\n        } else {\n            \/\/ \u5f53\u305f\u3063\u305f\u304c\u3001\u30c9\u30e9\u30c3\u30b0\u4e0d\u53ef\uff08\u4f8b\uff1a\u5e8a\uff09\u306e\u5834\u5408\n            selectedObject = null;\n            return;\n        }\n        \/\/ selectedObject \u306e Y\u4f4d\u7f6e (\u30d4\u30dc\u30c3\u30c8\u306e\u4f4d\u7f6e) \u3092\u53d6\u5f97\n        const objectY = selectedObject.position.y; \n        \/\/ \u30c9\u30e9\u30c3\u30b0\u5e73\u9762\u3068\u64cd\u4f5c\u30e2\u30fc\u30c9\u3092\u6c7a\u5b9a\n        if (selectedObject.userData.isLightControl || selectedObject.userData.isLightTargetControl) {\n            \/\/ \u30e9\u30a4\u30c8\u5236\u5fa1\u30e1\u30c3\u30b7\u30e5 (\u4f4d\u7f6e\/\u30bf\u30fc\u30b2\u30c3\u30c8) \u306e\u5834\u5408\u3001\u30ab\u30e1\u30e9\u8996\u7dda\u306b\u5782\u76f4\u306a\u5e73\u9762\u3067\u79fb\u52d5\uff083D\u30c9\u30e9\u30c3\u30b0\uff09\n            dragPlane = new THREE.Plane();\n            const worldPosition = new THREE.Vector3();\n            selectedObject.getWorldPosition(worldPosition);\n            \n            \/\/ \u30ab\u30e1\u30e9\u306e\u8996\u7dda\u65b9\u5411\u306b\u5782\u76f4\u306a\u5e73\u9762\u306e\u6cd5\u7dda\u3092\u8a2d\u5b9a\n            camera.getWorldDirection(dragPlane.normal); \n            dragPlane.normal.negate(); \n            \n            \/\/ \u5e73\u9762\u306e\u5b9a\u6570 (\u30ef\u30fc\u30eb\u30c9\u5ea7\u6a19\u3067\u306e\u8ddd\u96e2) \u3092\u8a08\u7b97\n            dragPlane.constant = -dragPlane.normal.dot(worldPosition);\n            \/\/ \u30e9\u30a4\u30c8\u5236\u5fa1\u30e1\u30c3\u30b7\u30e5\u306f\u5e38\u306b\u79fb\u52d5\u30e2\u30fc\u30c9\n            isDragging = true;\n            isRotating = false; \n            rotationGuide.visible = false;\n            offset.set(0, 0, 0); \n            \n        } else {\n            dragPlane = plane; \/\/ Y=0\u5e73\u9762\n            \/\/ Shift\u30ad\u30fc\u304c\u62bc\u3055\u308c\u3066\u3044\u305f\u3089\u56de\u8ee2\u30e2\u30fc\u30c9\u3001\u305d\u3046\u3067\u306a\u3051\u308c\u3070\u79fb\u52d5\u30e2\u30fc\u30c9\n            if (event.shiftKey) { \n                isRotating = true;\n                isDragging = false; \n                \n                \/\/ \u30ea\u30f3\u30b0\u306e\u9ad8\u3055\u3092\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30d4\u30dc\u30c3\u30c8 (Y\u4f4d\u7f6e) \u306b\u8a2d\u5b9a\n                rotationGuide.position.set(selectedObject.position.x, objectY, selectedObject.position.z);\n                rotationGuide.rotation.y = 0; \n                rotationGuide.visible = true;\n                updateExtensionLines(selectedObject, rotationGuide);\n            } else {\n                isDragging = true;\n                isRotating = false;\n\n                rotationGuide.visible = false;\n                \/\/ \u79fb\u52d5\u30e2\u30fc\u30c9\u306e\u5834\u5408\u306e\u307f\u30aa\u30d5\u30bb\u30c3\u30c8\u3092\u8a08\u7b97\n                if(raycaster.ray.intersectPlane(dragPlane, offset)){\n        \t\tisDragging = true;\n                }else{\n                        isDragging = false; \n                        selectedObject = null;\n                }\n            }\n        }        \n        controls.enabled = false;\n    } else {\n        \/\/ \u4f55\u3082\u9078\u629e\u3055\u308c\u306a\u304b\u3063\u305f\u5834\u5408\u306f\u3001\u9078\u629e\u3092\u89e3\u9664\u3001\u30ac\u30a4\u30c9\u3092\u975e\u8868\u793a\n        selectedObject = null;\n        isDragging = false;\n        isRotating = false;\n        rotationGuide.visible = false; \n        rotationGuide.children.find(c =&gt; c.userData.isExtension)?.clear();\n        controls.enabled = true;\n    }\n}\n\/\/ 10.\u30de\u30a6\u30b9\u304c\u79fb\u52d5\u3057\u305f\u3068\u304d (\u30c9\u30e9\u30c3\u30b0\u4e2d)\nfunction onPointerMove(event) {\n    \n    if (!selectedObject) return;\n\n    updateMouse(event);\n    raycaster.setFromCamera(mouse, camera);\n    \n    const objectY = selectedObject.position.y; \n    \n    if (isDragging) { \/\/ === \u79fb\u52d5\u30ed\u30b8\u30c3\u30af ===\n        let intersection = new THREE.Vector3();\n        if (raycaster.ray.intersectPlane(dragPlane, intersection)) {\n            \n            if (selectedObject.userData.isLightControl) {\n                \/\/ \u30e9\u30a4\u30c8\u5236\u5fa1\u30e1\u30c3\u30b7\u30e5 (\u4f4d\u7f6e): 3D\u7a7a\u9593\u3067\u81ea\u7531\u306b\u79fb\u52d5\n                selectedObject.position.copy(intersection);\n                spotLight.position.copy(selectedObject.position); \/\/ \u30e9\u30a4\u30c8\u306e\u4f4d\u7f6e\u3082\u66f4\u65b0\n                \n            } else if (selectedObject.userData.isLightTargetControl) {\n                \/\/ \u30e9\u30a4\u30c8\u30bf\u30fc\u30b2\u30c3\u30c8\u30e1\u30c3\u30b7\u30e5 (\u5411\u304d): 3D\u7a7a\u9593\u3067\u81ea\u7531\u306b\u79fb\u52d5\n                selectedObject.position.copy(intersection);\n                \/\/ SpotLight\u306e\u30bf\u30fc\u30b2\u30c3\u30c8\u4f4d\u7f6e\u306fanimate()\u3067\u66f4\u65b0\u3055\u308c\u308b\n            } else {\n                \/\/ \u5bb6\u5177: Y=0\u5e73\u9762\u4e0a\u3067\u306e\u79fb\u52d5\n                \/\/ 1. \u73fe\u5728\u306e\u4ea4\u70b9 (intersection) \u3068\u524d\u56de\u306e\u4ea4\u70b9 (offset) \u306e\u5dee\u5206\u3092\u8a08\u7b97\n                const delta = intersection.clone().sub(offset); \/\/ delta = World_Move_Vector\n                \/\/ 2. \u9078\u629e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u73fe\u5728\u306e\u4f4d\u7f6e (\u30ed\u30fc\u30ab\u30eb) \u306b\u5dee\u5206\u3092\u52a0\u3048\u308b\n                selectedObject.position.add(delta);\n                \/\/ 3. Y\u4f4d\u7f6e\u3092\u5143\u306e\u9ad8\u3055\u306b\u56fa\u5b9a\n                selectedObject.position.y = objectY; \n                \/\/ 4. \u6b21\u306e\u30d5\u30ec\u30fc\u30e0\u306e\u305f\u3081\u306b offset \u3092\u73fe\u5728\u306e\u4ea4\u70b9\u306b\u66f4\u65b0\n                offset.copy(intersection);\n\n                if (rotationGuide.visible) {\n                     rotationGuide.position.set(selectedObject.position.x, objectY, selectedObject.position.z);\n                }\n            }\n        }\n    } else if (isRotating) { \/\/ === \u56de\u8ee2\u30ed\u30b8\u30c3\u30af (\u56de\u8ee2\u30ac\u30a4\u30c9\u3078\u306e Raycast\u306b\u3088\u308b\u89d2\u5ea6\u6307\u5b9a) ===\n        const guideRing = rotationGuide.children.find(c =&gt; c.type === 'Mesh');\n\n        if (guideRing) {\n            const intersects = raycaster.intersectObject(guideRing, true);\n            if (intersects.length &gt; 0) {\n                const intersectionPoint = intersects[0].point;\n                const centerPoint = selectedObject.position.clone();\n                const vector = intersectionPoint.clone().sub(centerPoint);\n                \n                let newAngleRad = Math.atan2(vector.x, vector.z); \n                \n                const snappedAngleDeg = Math.round(THREE.MathUtils.radToDeg(newAngleRad));\n                const finalAngleRad = THREE.MathUtils.degToRad(snappedAngleDeg);\n                selectedObject.rotation.y = finalAngleRad;\n                rotationGuide.position.copy(selectedObject.position);\n                \n                updateExtensionLines(selectedObject, rotationGuide);\n            }\n        }\n    }\n}\n\/\/ 11.\u30de\u30a6\u30b9\u30dc\u30bf\u30f3\u304c\u96e2\u3055\u308c\u305f\u3068\u304d (\u7d42\u4e86)\nfunction onPointerUp(event) {\n    if (isDragging || isRotating) { \n        isDragging = false;\n        isRotating = false;\n        selectedObject = null;\n        \/\/ \u30ac\u30a4\u30c9\u3092\u975e\u8868\u793a\u306b\u3059\u308b\n        rotationGuide.visible = false;\n        rotationGuide.children.find(c =&gt; c.userData.isExtension)?.clear();\n        \/\/ \u30ab\u30e1\u30e9\u64cd\u4f5c\u3092\u518d\u6709\u52b9\u5316\n        controls.enabled = true;\n    }\n}\n\/\/ 12.\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u73fe\u5728\u306e\u56de\u8ee2\u306b\u5408\u308f\u305b\u3066\u5f15\u304d\u51fa\u3057\u30ac\u30a4\u30c9\u7dda\u3092\u4f5c\u6210\u30fb\u66f4\u65b0\u3059\u308b\nfunction updateExtensionLines(object, guide) {\n    const ringInnerRadius = 2.8; \n    const extensionLinesGroup = guide.children.find(c =&gt; c.userData.isExtension);\n    if (!extensionLinesGroup) return;\n    extensionLinesGroup.clear(); \n    const lineMaterial = new THREE.LineBasicMaterial({ color: 0xff0000, linewidth: 2 });\n    \n    const rotationMatrix = new THREE.Matrix4().makeRotationY(object.rotation.y);\n    \n    \/\/ 1. Z\u8ef8\u65b9\u5411\u306e\u7dda\n    const startZ = new THREE.Vector3(0, 0, -ringInnerRadius);\n    const endZ = new THREE.Vector3(0, 0, ringInnerRadius);\n    startZ.applyMatrix4(rotationMatrix); \n    endZ.applyMatrix4(rotationMatrix); \n    const pointsZ = [];\n    pointsZ.push(startZ);\n    pointsZ.push(endZ);\n    const geoZ = new THREE.BufferGeometry().setFromPoints(pointsZ);\n    const lineZ = new THREE.Line(geoZ, lineMaterial);\n    \n    \/\/ 2. X\u8ef8\u65b9\u5411\u306e\u7dda \n    const startX = new THREE.Vector3(-ringInnerRadius, 0, 0);\n    const endX = new THREE.Vector3(ringInnerRadius, 0, 0);\n    startX.applyMatrix4(rotationMatrix); \n    endX.applyMatrix4(rotationMatrix); \n    const pointsX = [];\n    pointsX.push(startX);\n    pointsX.push(endX);\n    const geoX = new THREE.BufferGeometry().setFromPoints(pointsX);\n    const lineX = new THREE.Line(geoX, lineMaterial);\n    extensionLinesGroup.add(lineZ);\n    extensionLinesGroup.add(lineX);\n}\n\/\/ 13.\u56de\u8ee2\u30ac\u30a4\u30c9\uff08\u30ea\u30f3\u30b0\u3068\u76ee\u76db\uff09\u3092\u4f5c\u6210\u3059\u308b \nfunction createRotationGuide() {\n    const guideGroup = new THREE.Group();\n    \n    const innerRadius = 2.8; \n    const outerRadius = 3.3; \n    const segments = 360;    \n    \n    \/\/ 1. \u30ea\u30f3\u30b0\u672c\u4f53 (Raycast\u30bf\u30fc\u30b2\u30c3\u30c8)\n    const ringGeometry = new THREE.RingGeometry(innerRadius, outerRadius, segments, 1, 0, Math.PI * 2);\n    const ringMaterial = new THREE.MeshBasicMaterial({ \n        color: 0xffff00, \n        side: THREE.DoubleSide,\n        transparent: true,\n        opacity: 0.8\n    });\n    const ring = new THREE.Mesh(ringGeometry, ringMaterial);\n    ring.rotation.x = Math.PI \/ 2;\n    ring.position.y = 0.05; \n    guideGroup.add(ring);\n    \/\/ 2. 5\u5ea6\u3054\u3068\u306e\u76ee\u76db\u7dda\u3092\u4f5c\u6210\n    const majorLineMaterial = new THREE.LineBasicMaterial({ color: 0x000000, linewidth: 3 }); \n    const minorLineMaterial = new THREE.LineBasicMaterial({ color: 0x000000, linewidth: 1 }); \n    \n    const majorLineVertices = []; \n    const minorLineVertices = []; \n    \n    for (let i = 0; i  {\n        dialog.classList.add('hidden');\n    }, 2000);\n}\n\/\/ --- \u72b6\u614b\u4fdd\u5b58\u30fb\u8aad\u307f\u8fbc\u307f\u95a2\u6570 ---\n\/\/ 15.\u73fe\u5728\u306e\u5bb6\u5177\u3068\u30ab\u30e1\u30e9\u306e\u72b6\u614b\u3092\u53ce\u96c6\u3059\u308b\nfunction getFurnitureState() {\n    \/\/ \u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u306e\u4f4d\u7f6e\u3092state\u306b\u8ffd\u52a0\n    const lightState = {\n        id: spotLightControlMesh.userData.name,\n        position: {\n            x: spotLightControlMesh.position.x, \/\/ \u5236\u5fa1\u30e1\u30c3\u30b7\u30e5\u306e\u30ed\u30fc\u30ab\u30eb\u4f4d\u7f6e\u3092\u4fdd\u5b58\n            y: spotLightControlMesh.position.y,\n            z: spotLightControlMesh.position.z\n        }\n    };\n    \n    \/\/ \u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u306e\u30bf\u30fc\u30b2\u30c3\u30c8\u4f4d\u7f6e\u3092state\u306b\u8ffd\u52a0\n    const targetState = {\n        id: spotLightTargetControlMesh.userData.name,\n        position: {\n            x: spotLightTargetControlMesh.position.x, \/\/ \u5236\u5fa1\u30e1\u30c3\u30b7\u30e5\u306e\u30ed\u30fc\u30ab\u30eb\u4f4d\u7f6e\u3092\u4fdd\u5b58\n            y: spotLightTargetControlMesh.position.y,\n            z: spotLightTargetControlMesh.position.z\n        }\n    };\n    \n    \/\/ furniture\u914d\u5217\u306b\u306flightControlMesh\/targetControlMesh\u306f\u542b\u307e\u308c\u3066\u3044\u306a\u3044\u305f\u3081\u3001\u5225\u9014\u53ce\u96c6\n    const furnitureState = furniture.map(mesh =&gt; ({\n        id: mesh.userData.id,\n        position: {\n            \/\/ \u5bb6\u5177\u306froomGroup\u306e\u5b50\u8981\u7d20\u306a\u306e\u3067\u3001\u30ed\u30fc\u30ab\u30eb\u5ea7\u6a19\u3092\u4fdd\u5b58\n            x: mesh.position.x,\n            y: mesh.position.y,\n            z: mesh.position.z\n        },\n        rotation: {\n            y: mesh.rotation.y\n        }\n    }));\n    \n    return [lightState, targetState, ...furnitureState]; \/\/ \u30bf\u30fc\u30b2\u30c3\u30c8\u306e\u72b6\u614b\u3092\u8ffd\u52a0\n}\n\/\/ 16.\u4fdd\u5b58\u3055\u308c\u305f\u72b6\u614b\u3092\u5bb6\u5177\u3068\u30ab\u30e1\u30e9\u306b\u9069\u7528\u3059\u308b\nfunction setFurnitureState(state) {\n    if (!state || !state.furniture || state.furniture.length === 0) {\n        console.warn(\"No furniture state found to load.\");\n        return;\n    }\n    state.furniture.forEach(savedItem =&gt; {\n        \/\/ ID\u3067\u30e9\u30a4\u30c8\u306e\u4f4d\u7f6e\u3092\u691c\u7d22\n        if (savedItem.id === spotLightControlMesh.userData.name) {\n            spotLightControlMesh.position.set(savedItem.position.x, savedItem.position.y, savedItem.position.z);\n            spotLight.position.copy(spotLightControlMesh.position); \/\/ \u30e9\u30a4\u30c8\u81ea\u4f53\u3082\u66f4\u65b0\n            return;\n        }\n        \n        \/\/ ID\u3067\u30e9\u30a4\u30c8\u306e\u30bf\u30fc\u30b2\u30c3\u30c8\u3092\u691c\u7d22\n        if (savedItem.id === spotLightTargetControlMesh.userData.name) {\n            spotLightTargetControlMesh.position.set(savedItem.position.x, savedItem.position.y, savedItem.position.z);\n            \/\/ SpotLight\u306etarget\u306fanimate()\u3067\u66f4\u65b0\u3055\u308c\u308b\n            return;\n        }\n        \n        \/\/ ID\u3067\u5bb6\u5177\u3092\u691c\u7d22\n        const mesh = furniture.find(f =&gt; f.userData.id === savedItem.id);\n        \n        if (mesh) {\n            \/\/ \u4f4d\u7f6e\u3068\u56de\u8ee2\u3092\u9069\u7528\n            mesh.position.set(savedItem.position.x, savedItem.position.y, savedItem.position.z);\n            mesh.rotation.y = savedItem.rotation.y;\n        }\n    });\n    \/\/ \u30ab\u30e1\u30e9\u4f4d\u7f6e\u3068\u6ce8\u8996\u70b9\u3092\u9069\u7528\n    if (state.camera &amp;&amp; state.controlsTarget) {\n        camera.position.set(state.camera.x, state.camera.y, state.camera.z);\n        controls.target.set(state.controlsTarget.x, state.controlsTarget.y, state.controlsTarget.z);\n        controls.update();\n    }\n}\n\/\/ 17.\u73fe\u5728\u306e\u72b6\u614b\u3092 localStorage \u306b\u4fdd\u5b58\u3059\u308b\nfunction saveState() {\n    const state = {\n        furniture: getFurnitureState(),\n        camera: {\n            x: camera.position.x,\n            y: camera.position.y,\n            z: camera.position.z\n        },\n        controlsTarget: {\n            x: controls.target.x,\n            y: controls.target.y,\n            z: controls.target.z\n        }\n    };\n    \n    try {\n        localStorage.setItem('threejsLayoutState', JSON.stringify(state));\n        console.log('Layout state saved successfully!');\n        \/\/ \u6210\u529f\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u30ab\u30b9\u30bf\u30e0\u30c0\u30a4\u30a2\u30ed\u30b0\u3067\u8868\u793a\n        showCustomDialog('\u73fe\u5728\u306e\u4f4d\u7f6e\u3092\u4fdd\u5b58\u3057\u307e\u3057\u305f\u3002'); \n    } catch (e) {\n        console.error('Failed to save state to localStorage:', e);\n        showCustomDialog('\u30ec\u30a4\u30a2\u30a6\u30c8\u306e\u4fdd\u5b58\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002', true);\n    }\n}\n\/\/ 18.localStorage \u304b\u3089\u72b6\u614b\u3092\u8aad\u307f\u8fbc\u3080\nfunction loadState() {\n    try {\n        const savedState = localStorage.getItem('threejsLayoutState');\n        if (savedState) {\n            const state = JSON.parse(savedState);\n            setFurnitureState(state);\n            console.log('Layout state loaded successfully!');\n        } else {\n            console.log('No saved state found.');\n            showCustomDialog('\u4fdd\u5b58\u3055\u308c\u305f\u30ec\u30a4\u30a2\u30a6\u30c8\u306f\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002', true); \n        }\n    } catch (e) {\n        console.error('Failed to load state from localStorage:', e);\n        showCustomDialog('\u30ec\u30a4\u30a2\u30a6\u30c8\u306e\u8aad\u307f\u8fbc\u307f\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002', true);\n    }\n}\n\n\/\/ \u5b9f\u884c\ninit();\nanimate();\n\n<\/code><\/pre>\n\n\n<p><img decoding=\"async\" class=\"wp-image-49702\" style=\"width: 640px\" src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2025\/12\/webbase3d-16.png\" alt=\"VS Code\u5b9f\u884c\u7d50\u679c\u30fc\u30b9\u30dd\u30c3\u30c8\u30e9\u30a4\u30c8\u306e\u8868\u793a\"><\/p>\n\n\n\n<p>\u30aa\u30ec\u30f3\u30b8\u8272\u306e\u7403\u4f53\u3092\u3064\u307e\u3093\u3067\u52d5\u304b\u3057\u3066\u307f\u3066\u304f\u3060\u3055\u3044\u5149\u6e90\u304c\u79fb\u52d5\u3059\u308b\u306b\u4f34\u3063\u3066\u5f71\u306e\u4f4d\u7f6e\u3082\u5909\u5316\u3057\u307e\u3059\u3002\u5e8a\u306b\u3060\u3051\u3067\u306f\u306a\u304f\u58c1\u3001\u5bb6\u5177\u985e\u306b\u3082\u5f71\u304c\u843d\u3061\u307e\u3059\u3002<br>\u4fdd\u5b58\u6a5f\u80fd\u306f\u4e00\u6642\u7684\u306b\u30ed\u30fc\u30ab\u30eb\u306ePC\u4e0a\u306b\u4fdd\u5b58\u3055\u308c\u307e\u3059\u3002\uff08\u30d6\u30e9\u30a6\u30b6\u3092\u7d42\u4e86\u3059\u308b\u3068\u60c5\u5831\u306f\u6d88\u3048\u307e\u3059\uff09<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u307e\u3068\u3081<\/h2>\n\n\n\n<p>\u672c\u8a18\u4e8b\u3092\u901a\u3058\u3066\u3001\u79c1\u305f\u3061\u306fWeb\u30d6\u30e9\u30a6\u30b6\u4e0a\u3067\u52d5\u4f5c\u3059\u308b3D\u30ec\u30a4\u30a2\u30a6\u30c8\u30b7\u30df\u30e5\u30ec\u30fc\u30bf\u30fc\u306e\u57fa\u790e\u3092\u69cb\u7bc9\u3057\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<div class=\"wp-block-luxe-blocks-border-block\" style=\"margin-top:10px;margin-bottom:30px\"><div class=\"wp-block-luxe-blocks-border-block-content\" style=\"border:1px solid #006edc;border-radius:0px;padding:0px 15px 0px 15px\">\n<ol type=\"1\">\n<li>Three.js\u3068ES Modules\u3092\u4f7f\u7528\u3057\u3066\u3001\u30e2\u30c0\u30f3\u3067\u5b89\u5b9a\u3057\u305f\u958b\u767a\u74b0\u5883\u3092\u78ba\u7acb\u3057\u307e\u3057\u305f\u3002<\/li>\n\n\n\n<li>\u30b7\u30fc\u30f3\u3001\u30ab\u30e1\u30e9\u3001\u30ec\u30f3\u30c0\u30e9\u30fc\u3092\u8a2d\u5b9a\u3057\u30013D\u7a7a\u9593\u306e\u571f\u53f0\u3092\u4f5c\u6210\u3057\u307e\u3057\u305f\u3002<\/li>\n\n\n\n<li>\u30e9\u30a4\u30c8\u3068\u5e7e\u4f55\u5b66\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u7528\u3044\u3066\u3001\u90e8\u5c4b\u306e\u69cb\u9020\uff08\u5e8a\u3068\u58c1\uff09\u304a\u3088\u3073\u5bb6\u5177\u306e\u30d7\u30ec\u30fc\u30b9\u30db\u30eb\u30c0\u30fc\u3092\u4f5c\u6210\u3057\u307e\u3057\u305f\u3002<\/li>\n\n\n\n<li>3\uff24\u30e2\u30c7\u30eb\u30c4\u30fc\u30eb\u4f5c\u6210\u306e\u30e2\u30c7\u30eb\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u3093\u3067\u30b7\u30fc\u30f3\u306b\u914d\u7f6e\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3057\u305f\u3002<\/li>\n\n\n\n<li>\u6700\u3082\u91cd\u8981\u306a\u6a5f\u80fd\u3067\u3042\u308b<strong>Raycaster\u3092\u7528\u3044\u305f\u30c9\u30e9\u30c3\u30b0\uff06\u30c9\u30ed\u30c3\u30d7<\/strong>\u6a5f\u80fd\u306b\u3088\u308a\u3001\u5bb6\u5177\u3092\u30de\u30a6\u30b9\u64cd\u4f5c\u3067\u81ea\u7531\u306b\u914d\u7f6e\u30fb\u79fb\u52d5\u30fb\u56de\u8ee2\u3067\u304d\u308b\u30ec\u30a4\u30a2\u30a6\u30c8\u30c4\u30fc\u30eb\u3092\u5b9f\u73fe\u3057\u307e\u3057\u305f\u3002<\/li>\n\n\n\n<li>\u7c21\u6613\u7684\u306a\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u4f4d\u7f6e\u60c5\u5831\u3092\u4fdd\u5b58\u3001\u547c\u3073\u51fa\u3059\u3053\u3068\u304c\u3067\u304d\u307e\u3057\u305f\u3002<\/li>\n<\/ol>\n<\/div><\/div>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u57fa\u672c\u69cb\u9020\u304c\u3042\u308c\u3070\u3001\u3042\u306a\u305f\u306e\u30ec\u30a4\u30a2\u30a6\u30c8\u30c4\u30fc\u30eb\u306f\u3059\u3067\u306b\u5b9f\u7528\u306e\u4e00\u6b69\u3092\u8e0f\u307f\u51fa\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<p>Three.js\u306f\u4eca\u56de\u4f7f\u7528\u3057\u305f\u57fa\u672c\u7684\u306a\u95a2\u6570\u4ee5\u5916\u306b\u591a\u6570\u306e\u6709\u7528\u306a\u95a2\u6570\u304c\u7528\u610f\u3055\u308c\u3066\u3044\u307e\u3059\u3002<a href=\"https:\/\/threejs.org\/\" data-type=\"link\" data-id=\"https:\/\/threejs.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">Three.js\u306e\u516c\u5f0f\u30b5\u30a4\u30c8<\/a>\u3092\u53c2\u8003\u306b\u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0\u306e\u5b66\u7fd2\u65b9\u6cd5\u306b\u3064\u3044\u3066<\/h3>\n\n\n\n<p>\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0\u306e\u5b66\u7fd2\u65b9\u6cd5\u306f\u6642\u4ee3\u3068\u3068\u3082\u306b\u5927\u304d\u304f\u5909\u5316\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<ul class=\"has-whitesmoke-background-color has-background\">\n<li><strong>\u5f93\u6765\u306e\u5b66\u7fd2\u65b9\u6cd5:<\/strong>\u53e4\u304f\u306f<strong>\u6280\u8853\u66f8<\/strong>\u3084<strong>\u5c02\u9580\u96d1\u8a8c<\/strong>\u304b\u3089\u77e5\u8b58\u3092\u5f97\u3066\u3044\u307e\u3057\u305f\u3002\u305d\u306e\u5f8c\u3001\u30a4\u30f3\u30bf\u30fc\u30cd\u30c3\u30c8\u306e\u666e\u53ca\u306b\u4f34\u3044\u3001\u6280\u8853\u7d39\u4ecb\u30d6\u30ed\u30b0\uff08\u4f8b\uff1aQiita\uff09<strong>\u3084<\/strong>\u30aa\u30fc\u30d7\u30f3\u30bd\u30fc\u30b9\u306e\u30b3\u30fc\u30c9\uff08\u4f8b\uff1aGitHub\uff09\u3092\u53c2\u8003\u306b\u3057\u306a\u304c\u3089\u72ec\u5b66\u3067\u30b9\u30ad\u30eb\u3092\u7fd2\u5f97\u3059\u308b\u306e\u304c\u4e3b\u6d41\u3068\u306a\u308a\u307e\u3057\u305f\u3002<\/li>\n\n\n\n<li><strong>\u6700\u65b0\u306e\u5b66\u7fd2\u65b9\u6cd5\uff08\u751f\u6210AI\u306e\u6d3b\u7528\uff09:<\/strong>\u73fe\u5728\u3067\u306f\u305d\u308c\u306b\u52a0\u3048\u3066\u3001\u751f\u6210AI\uff08\u4f8b\uff1aChatGPT\u3001GitHub Copilot\uff09\u306b\u5b9f\u73fe\u3057\u305f\u3044\u6a5f\u80fd\u3092\u30a4\u30f3\u30d7\u30c3\u30c8\u3057\u3001<strong>\u30b3\u30fc\u30c9\u3092\u751f\u6210\u3055\u305b\u306a\u304c\u3089\u305d\u306e\u4ed5\u7d44\u307f\u3092\u7406\u89e3\u3059\u308b<\/strong>\u3001\u3068\u3044\u3046\u65b0\u3057\u3044\u5b66\u7fd2\u30b9\u30bf\u30a4\u30eb\u3082\u78ba\u7acb\u3055\u308c\u3066\u304d\u3066\u3044\u307e\u3059\u3002\u3055\u3089\u306b\u3001AI\u304c\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u5168\u4f53\u3092\u4f5c\u6210\u3059\u308b\u300c<strong>AI\u99c6\u52d5\u958b\u767a<\/strong>\u300d\u306e\u6642\u4ee3\u306b\u7a81\u5165\u3057\u3066\u3044\u307e\u3059\u3002<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">AI\u6642\u4ee3\u306b\u6c42\u3081\u3089\u308c\u308b\u30b9\u30ad\u30eb<\/h3>\n\n\n\n<p>\u3057\u304b\u3057\u3001AI\u304c\u30b3\u30fc\u30c9\u3092\u751f\u6210\u3057\u3066\u304f\u308c\u308b\u304b\u3089\u3068\u3044\u3063\u3066\u3001\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0\u30b9\u30ad\u30eb\u304c\u4e0d\u8981\u306b\u306a\u3063\u305f\u308f\u3051\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002<\/p>\n\n\n\n<p>\u751f\u6210\u3055\u308c\u305f\u30b3\u30fc\u30c9\u304c<strong>\u610f\u56f3\u901a\u308a\u306b\u52d5\u4f5c\u3059\u308b\u304b\u3092\u691c\u8a3c<\/strong>\u3057\u3001<strong>\u30d0\u30b0\u3092\u4fee\u6b63<\/strong>\u3057\u305f\u308a\u3001<strong>\u3088\u308a\u52b9\u7387\u7684\u306a\u5f62\u306b\u6539\u5584<\/strong>\u3057\u305f\u308a\u3059\u308b\u305f\u3081\u306b\u306f\u3001\u305d\u306e\u30b3\u30fc\u30c9\u3092<strong>\u6b63\u3057\u304f\u7406\u89e3\u3059\u308b\u30b9\u30ad\u30eb<\/strong>\u304c\u4e0d\u53ef\u6b20\u3067\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u307e\u305a\u306f\u4e00\u3064\u306e\u8a00\u8a9e\u3092\u6975\u3081\u308b<\/h3>\n\n\n\n<p>\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0\u8a00\u8a9e\u306e\u57fa\u672c\u7684\u306a\u8003\u3048\u65b9\uff08\u30ed\u30b8\u30c3\u30af\u3084\u69cb\u6587\uff09\u306f\u3001\u8a00\u8a9e\u304c\u5909\u308f\u3063\u3066\u3082\u5171\u901a\u3057\u3066\u3044\u307e\u3059\u3002<br>\u305d\u306e\u305f\u3081\u3001<strong>\u4e00\u3064\u306e\u8a00\u8a9e\u306b\u6df1\u304f\u7cbe\u901a<\/strong>\u3057\u3066\u304a\u3051\u3070\u3001\u4ed6\u306e\u8a00\u8a9e\u3092\u5b66\u3076\u969b\u306b\u3082\u540c\u69d8\u306e\u8003\u3048\u65b9\u3067\u30b9\u30e0\u30fc\u30ba\u306b\u7fd2\u5f97\u304c\u53ef\u80fd\u3067\u3059\u3002<\/p>\n\n\n\n<p>\u3053\u308c\u304b\u3089\u5b66\u7fd2\u3092\u59cb\u3081\u308b\u65b9\u306b\u306f\u3001<strong>\u6c4e\u7528\u6027\u304c\u9ad8\u304f\u3001AI\u5206\u91ce\u3067\u3082\u5e83\u304f\u4f7f\u308f\u308c\u3066\u3044\u308bPython<\/strong>\u306a\u3069\u306e\u8a00\u8a9e\u304b\u3089\u7fd2\u5f97\u3059\u308b\u3053\u3068\u3092\u304a\u3059\u3059\u3081\u3057\u307e\u3059\u3002\u307e\u305a\u306f\u300c\u3053\u308c\u306a\u3089\u5b8c\u74a7\u306b\u4f7f\u3048\u308b\u300d\u3068\u3044\u3046\u8a00\u8a9e\u3092\u4e00\u3064\u8eab\u306b\u3064\u3051\u307e\u3057\u3087\u3046\u3002<\/p>\n\n\n\n<p><strong>\u4eca\u56de\u306e\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u4e00\u5f0f\u306f\u4ee5\u4e0b\u306b\u30a2\u30c3\u30d7\u3057\u3066\u304a\u304d\u307e\u3059\u3002<\/strong><br><a href=\"https:\/\/github.com\/picolix\/Three.js-Room-Layout-Editor\/archive\/refs\/heads\/main.zip\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/picolix\/Three.js-Room-Layout-Editor\/archive\/refs\/heads\/main.zip<\/a><br><strong>\u5404\u6a5f\u80fd\u6bb5\u968e\u3067\u306emain.js\u3082\u540c\u68b1\u3057\u3066\u3044\u307e\u3059\u306e\u3067\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u5185\u306e\u30b3\u30e1\u30f3\u30c8\u3092\u307f\u306a\u304c\u3089\u7406\u89e3\u3092\u542b\u3081\u3066\u304f\u3060\u3055\u3044\u3002<\/strong><\/p>\n\n\n\n<div class=\"wp-block-luxe-blocks-topic\" style=\"margin-top:10px;margin-bottom:30px\"><div class=\"wp-block-luxe-blocks-topic-title\" style=\"color:#fff;background-color:#006edc;border:1px solid #006edc;padding:2px 14px;align-items:center\">\u3042\u306a\u305f\u306e\u4f5c\u54c1\u3092\u516c\u958b\u3057\u3066\u307f\u307e\u3057\u3087\u3046<\/div><div class=\"wp-block-luxe-blocks-topic-content\" style=\"border:1px solid #006edc;padding:0px 15px 0px 15px\">\n\n<p>\u5b8c\u6210\u3057\u305f3D\u30ec\u30a4\u30a2\u30a6\u30c8\u30c4\u30fc\u30eb\u3092\u3001\u53cb\u4eba\u3084\u540c\u50da\u3001\u63a1\u7528\u62c5\u5f53\u8005\u306b\u898b\u305b\u305f\u3044\u3068\u601d\u3044\u307e\u305b\u3093\u304b\uff1f<\/p>\n\n\n<ul>\n\n<li>\u7121\u6599\u3067\u306f\u3058\u3081\u308b\u306a\u3089<a id=\"vn_cta_lp_xrea\" class=\"ga_event_link\" style=\"{style}\" href=\"https:\/\/www.xrea.com\/\">XREA<\/a><br>\u958b\u767a\u3057\u305f\u30d5\u30a1\u30a4\u30eb\u3092\u305d\u306e\u307e\u307e\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3059\u308b\u3060\u3051\u3067\u3001\u3059\u3050\u306b\u516c\u958b\u53ef\u80fd\u3067\u3059\u3002<\/li>\n\n\n<li>\u672c\u683c\u904b\u7528\u306a\u3089<a id=\"vn_cta_lp_core\" class=\"ga_event_link\" style=\"{style}\" href=\"https:\/\/www.coreserver.jp\/\">\u30b3\u30a2\u30b5\u30fc\u30d0\u30fc<\/a><br><strong>\u6708\u984d390\u5186\uff5e<\/strong>\u3067500GB\u306e\u5927\u5bb9\u91cf <br><strong>\u30c9\u30e1\u30a4\u30f3\u6c38\u4e45\u7121\u6599<\/strong>\uff1a\u30b5\u30fc\u30d0\u30fc\u3068\u30c9\u30e1\u30a4\u30f3\u540c\u6642\u7533\u3057\u8fbc\u307f\u3067\u3001\u30c9\u30e1\u30a4\u30f3\u8cbb\u7528\u304c<strong>\u6c38\u4e45\u7121\u6599<\/strong><br><strong>30\u65e5\u9593\u7121\u6599\u304a\u8a66\u3057<\/strong>\uff1a\u30ea\u30b9\u30af\u30bc\u30ed\u3067\u6027\u80fd\u3092\u4f53\u9a13\u3067\u304d\u308b<\/li>\n\n<\/ul>\n\n\n<p>\u3042\u306a\u305f\u306e3D\u4f5c\u54c1\u304c\u3001\u6b21\u306e\u30ad\u30e3\u30ea\u30a2\u3078\u306e\u6249\u3092\u958b\u304f\u304b\u3082\u3057\u308c\u307e\u305b\u3093\uff01<\/p>\n\n\n<div class=\"wp-block-buttons\"><div class=\"wp-block-button has-custom-width wp-block-button__width-100 btn-service core\">\n<a id=\"vn_cta_btn_lp_core\" class=\"ga_event_link wp-block-button__link has-white-color\" href=\"https:\/\/www.coreserver.jp\/\" style=\"background-color:#de5916\" target=\"_blank\" rel=\"noreferrer noopener\">\u30b3\u30a2\u30b5\u30fc\u30d0\u30fc\u516c\u5f0f\u30b5\u30a4\u30c8\u3092\u307f\u308b<\/a><\/div><\/div>\n\n<\/div><\/div>\n\n\n\n<div style=\"padding: 15px 12px 10px; font-size: 1em; background: #ffffe0; width: 100\uff05; height: 100\uff05;\"><span style=\"background-color: #ffffe0; color: #333;\"><span class=\"font-size\" style=\"font-size: 18px;\"><span class=\"has-inline-color\" style=\"color: #ff8c00;\"><strong>\u25bd\u30ad\u30e3\u30f3\u30da\u30fc\u30f3\u958b\u50ac\u4e2d\uff01<\/strong><\/span><\/span><\/span><\/div>\n<div style=\"padding: 15px 12px 10px; font-size: 1em; background: #ffffe0; width: 100\uff05; height: 100\uff05;\"><span style=\"background-color: #ffffe0; color: #333;\"><span data-sheets-formula-bar-text-style=\"color:#000000;font-weight:normal;text-decoration:none;font-family:'Arial';font-style:normal;text-decoration-skip-ink:none;\">\u30b3\u30a2\u30b5\u30fc\u30d0\u30fc\u3067\u306f\u3001V2\u30d7\u30e9\u30f3\uff08CORE-X,Y,Z\uff09\u3068\u30c9\u30e1\u30a4\u30f3\u306e\u540c\u6642\u7533\u3057\u8fbc\u307f\u3067<br \/><span style=\"color: #333333;\">\u30c9\u30e1\u30a4\u30f3\u304c<\/span><span class=\"text-color\" style=\"color: #ff0000;\"><strong>\u5b9f\u8cea<span style=\"font-size: 1.3em;\">0<\/span>\u5186\uff08\u5e74\u9593\u6700\u5927<span style=\"font-size: 1.3em;\">3,889<\/span>\u5186\u304a\u5f97\uff09<\/strong><\/span>\u306b\u306a\u308b<strong>\u30b5\u30fc\u30d0\u30fc\u30bb\u30c3\u30c8\u5272\u7279\u5178<\/strong><\/span><\/span><span style=\"background-color: #ffffe0; color: #333;\"><span data-sheets-formula-bar-text-style=\"color:#000000;font-weight:normal;text-decoration:none;font-family:'Arial';font-style:normal;text-decoration-skip-ink:none;\"><span style=\"color: #333333;\">\u3092\u5c55\u958b\u4e2d\u3067\u3059\u3002<br \/><\/span><\/span><\/span><\/div>\n<div style=\"padding: 15px 12px 10px; font-size: 1em; background: #ffffe0; width: 100\uff05; height: 100\uff05;\"><span style=\"background-color: #ffffe0; color: #333;\"><span data-sheets-formula-bar-text-style=\"color:#000000;font-weight:normal;text-decoration:none;font-family:'Arial';font-style:normal;text-decoration-skip-ink:none;\">\u662f\u975e\u3001\u304a\u5f97\u306a\u3053\u306e\u6a5f\u4f1a\u306b\u3054\u5229\u7528\u304f\u3060\u3055\u3044\uff01<br \/><span style=\"color: #333333;\">\u6700\u65b0\u306e\u30ad\u30e3\u30f3\u30da\u30fc\u30f3\u306f<\/span><\/span><span style=\"font-size: 1.3em;\"><a style=\"color: ff0000;\" href=\"https:\/\/www.value-domain.com\/media\/2022campaign-all\/\" target=\"_blank\" rel=\"noopener\"><strong>\u3053\u3061\u3089<\/strong><\/a><\/span>\u304b\u3089<br \/><\/span><\/div>\n<p><!-- wp:paragraph --><\/p>\n<p><a href=\"https:\/\/www.coreserver.jp\/\" target=\"_blank\" class=\"bnr_inner_area ga_event_banner\" id=\"vn_cta_lp_core\"><img src=\"https:\/\/media.value-domain.com\/wp-content\/uploads\/sites\/2\/2024\/06\/core_bnr2.png\" alt=\"\u8d85\u9ad8\u901f\u5316\u3092\u5b9f\u73fe\u3059\u308b\u30ec\u30f3\u30bf\u30eb\u30b5\u30fc\u30d0\u30fc CORESERVER\" width=\"{width}\" height=\"{height}\"><\/a><\/p>\n<p><!-- \/wp:paragraph --><\/p>\n\n\n\n<p>\u203b<a href=\"\/media\/user-note\/\" target=\"_blank\" >\u30e6\u30fc\u30b6\u30fc\u30ce\u30fc\u30c8<\/a>\u306e\u8a18\u4e8b\u306f\u3001\u5f0a\u793e\u30b5\u30fc\u30d3\u30b9\u3092\u3054\u5229\u7528\u306e\u304a\u5ba2\u69d8\u306b\u57f7\u7b46\u3044\u305f\u3060\u3044\u3066\u304a\u308a\u307e\u3059\u3002<\/p>\n<div style=\"border: 1px solid #8fa2b2; padding: 5px 20px; border-radius: 4px 4px 0 0; background: #8fa2b2;\"><span style=\"color: #ffffff;\">\u57f7\u7b46\u8005\uff1a\u82d7\u5834 \u7fd4\u69d8<\/span><\/div>\n<div style=\"border: 1px solid #8fa2b2; padding: 0px 20px; border-radius: 0 0 4px 4px; background: #ffffff;\">\n<p>\u533b\u7642\u30e1\u30fc\u30ab\u30fc\u3067\u65b0\u7d20\u6750\u7814\u7a76\u958b\u767a\u5f8c\u3001\u96fb\u6a5f\u30e1\u30fc\u30ab\u30fc\u3067\u5236\u5fa1\u5668\u7cfb\u30b7\u30b9\u30c6\u30e0\u958b\u767a\u3092\u7d4c\u3066IT\u7cfb\u30de\u30eb\u30c1\u30a8\u30f3\u30b8\u30cb\u30a2\u3092\u3057\u3066\u3044\u307e\u3059\u3002\u307e\u305f\u30c7\u30b6\u30a4\u30f3\u601d\u8003\u3092\u5b9f\u8df5\u3057\u3001\u30a2\u30fc\u30c8\u601d\u8003\u306a\u3069\u306e\u3044\u308d\u3093\u306a\u601d\u8003\u65b9\u6cd5\u306b\u8208\u5473\u304c\u3042\u308a\u307e\u3059\u3002<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>\u306f\u3058\u3081\u306b \u5bb6\u5177\u306e\u914d\u7f6e\u3092\u8003\u3048\u305f\u3044\u3001\u65b0\u3057\u3044\u30aa\u30d5\u30a3\u30b9\u306e\u30ec\u30a4\u30a2\u30a6\u30c8\u3092\u8a08\u753b\u3057\u305f\u3044\u3001\u3042\u308b\u3044\u306f\u30b2\u30fc\u30e0\u306e\u30b9\u30c6\u30fc\u30b8\u3092\u4f5c\u3063\u3066\u307f\u305f\u3044\u3002\u305d\u3093\u306a\u3068\u304d\u3001\u982d\u306e\u4e2d\u306e\u30a4\u30e1\u30fc\u30b8\u3092\u5b9f\u969b\u306b\u300c\u898b\u3048\u308b\u5316\u300d\u3067\u304d\u305f\u3089\u4fbf\u5229\u3060\u3068\u601d\u3044\u307e\u305b\u3093\u304b\uff1f\u305d\u3046\u3044\u3063\u305f\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306f\u6ca2 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":12526,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[15],"tags":[],"acf":[],"_links":{"self":[{"href":"https:\/\/media.value-domain.com\/wp-json\/wp\/v2\/posts\/12476"}],"collection":[{"href":"https:\/\/media.value-domain.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/media.value-domain.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/media.value-domain.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/media.value-domain.com\/wp-json\/wp\/v2\/comments?post=12476"}],"version-history":[{"count":14,"href":"https:\/\/media.value-domain.com\/wp-json\/wp\/v2\/posts\/12476\/revisions"}],"predecessor-version":[{"id":12527,"href":"https:\/\/media.value-domain.com\/wp-json\/wp\/v2\/posts\/12476\/revisions\/12527"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/media.value-domain.com\/wp-json\/wp\/v2\/media\/12526"}],"wp:attachment":[{"href":"https:\/\/media.value-domain.com\/wp-json\/wp\/v2\/media?parent=12476"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/media.value-domain.com\/wp-json\/wp\/v2\/categories?post=12476"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/media.value-domain.com\/wp-json\/wp\/v2\/tags?post=12476"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}