bricks/examples/scene3d_demo.html
yumoqing d945e414d7 feat(scene3d): Scene3D widget — bricks3d 最小闭环(后端声明式场景描述符→three.js 本地渲染→entity_tapped 事件回传)
- scene3d.js: Scene3D widget(VBox 子类),支持 box/sphere/cylinder/model 实体
  内联 scene 或 scene_url 两种描述符来源;Raycaster 拾取→dispatch entity_tapped
  活动对象(scene/camera/renderer/mesh)只存实例私有字段,防 JSON.stringify 循环引用
  s3_dispose() 释放 WebGL 资源;set_entity_color/set_entity_visible 公共 API
- build.sh: scene3d.js 加入 SOURCES
- 3parties/three.min.js: r149 UMD 全局版(608KB,npmmirror 下载)
- examples/scene3d_demo.html: 演示页(4 实体场景 + scene_ready/entity_tapped binds)

验证(CDP 实测):场景就绪事件 点击拾取 entity_tapped→binds→状态栏更新
球点击变色 #f59e0b→#ef4444 全链路通过;干净重载 0 JS 异常
2026-08-27 11:31:10 +08:00

62 lines
2.7 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>bricks3d Scene3D 最小闭环演示</title>
<link rel="stylesheet" href="/bricks/css/bricks.css" />
<style>html,body{margin:0;height:100%;background:#0d0d14}</style>
</head>
<body>
<script src="/bricks/3parties/three.min.js"></script>
<script src="/bricks/bricks.js"></script>
<script>
// 后端声明式场景描述符(实际部署时由 .dspy 返回,走 scene_url
var demo_scene = {
"camera": {"position": [8, 6, 10], "fov": 50},
"entities": [
{"id": "door", "name": "门", "type": "box",
"transform": {"pos": [-3, 1, 0], "rot": [0, 30, 0], "scale": [1.2, 2, 0.3]},
"appearance": {"color": "#3b82f6"}},
{"id": "ball", "name": "铃铛球", "type": "sphere",
"transform": {"pos": [0, 0.6, 2], "rot": [0, 0, 0], "scale": [1.2, 1.2, 1.2]},
"appearance": {"color": "#f59e0b"}},
{"id": "pillar", "name": "立柱", "type": "cylinder",
"transform": {"pos": [3, 1, -1], "rot": [0, 0, 0], "scale": [0.8, 2, 0.8]},
"appearance": {"color": "#10b981"}},
{"id": "crate", "name": "木箱", "type": "model",
"transform": {"pos": [0.5, 0.5, -2.5], "rot": [0, 45, 0], "scale": [1, 1, 1]},
"appearance": {"color": "#a16207"}}
]
};
const opts = {
"widget": {
"widgettype": "VBox",
"options": {"width": "100%", "height": "100%", "css": "filler"},
"subwidgets": [
{"widgettype": "HBox",
"options": {"height": "44px", "alignItems": "center", "gap": "10px", "padding": "0 12px"},
"subwidgets": [
{"widgettype": "Text", "id": "status_label",
"options": {"text": "加载中...", "color": "#94a3b8", "halign": "left"}}
]},
{"widgettype": "Scene3D", "id": "scene",
"options": {"scene": demo_scene, "css": "filler",
"binds_demo_note": "entity_tapped 走 binds"}}
],
"binds": [
{"wid": "scene", "event": "scene_ready", "actiontype": "script", "target": "status_label",
"script": "this.set_text('✅ 场景就绪:' + params.entity_count + ' 个实体(点击任意实体)');"},
{"wid": "scene", "event": "entity_tapped", "actiontype": "script", "target": "status_label",
"script": "var sc=bricks.getWidgetById('scene',bricks.app);var colors=['#ef4444','#3b82f6','#f59e0b','#10b981','#a855f7'];var c=colors[Math.floor(Math.random()*colors.length)];sc.set_entity_color(params.entity_id,c);this.set_text('🖱 点击了「' + params.entity_name + '」→ 已变色entity_tapped 事件回传成功)');"},
{"wid": "scene", "event": "scene_error", "actiontype": "script", "target": "status_label",
"script": "this.set_text('❌ 场景错误:' + params.message);"}
]
}
};
const app = new bricks.App(opts);
app.run();
</script>
</body>
</html>