look ma, theres 3D now

This commit is contained in:
STEINNI
2025-09-25 20:47:58 +00:00
parent 7c6047462f
commit 73e2b5a762
11 changed files with 78778 additions and 61 deletions
+140
View File
@@ -0,0 +1,140 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Three.js + OrbitControls (importmap)</title>
<style>
body { margin: 0; overflow: hidden; }
canvas { display: block; }
</style>
</head>
<body>
<!-- Import map tells browser where "three" lives -->
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js"
}
}
</script>
<script type="module">
import * as THREE from "three"
import { OrbitControls } from "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/controls/OrbitControls.js"
// Scene
const scene = new THREE.Scene()
scene.background = new THREE.Color(0x202080)
// Camera
const perspCam = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
perspCam.position.set(3, 3, 5)
const aspect = window.innerWidth / window.innerHeight
const frustumSize = 10
const cam2d = new THREE.OrthographicCamera(
-frustumSize * aspect / 2,
frustumSize * aspect / 2,
frustumSize / 2,
-frustumSize / 2,
0.1,
1000
)
cam2d.position.set(0, 100, 0)
cam2d.lookAt(0, 0, 0)
let activeCam = perspCam
// Renderer
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
// Cube
const geometry = new THREE.BoxGeometry()
const material = new THREE.MeshStandardMaterial({ color: 'red' })
const cube = new THREE.Mesh(geometry, material)
scene.add(cube)
cube.position.x+=2
// Light
const light = new THREE.DirectionalLight(0xffffff, 1)
light.position.set(5, 5, 5)
light.intensity = 2
scene.add(light)
this.scene.add(new THREE.AmbientLight(0xffffff, 0.4))
const snowman = new THREE.Group()
// Bottom sphere
const bottom = new THREE.Mesh(
new THREE.SphereGeometry(1, 32, 32),
new THREE.MeshStandardMaterial({ color: 'white' })
)
snowman.add(bottom)
// Middle sphere
const middle = new THREE.Mesh(
new THREE.SphereGeometry(0.7, 32, 32),
new THREE.MeshStandardMaterial({ color: 'white' })
)
middle.position.y = 1.3
snowman.add(middle)
// Head
const head = new THREE.Mesh(
new THREE.SphereGeometry(0.5, 32, 32),
new THREE.MeshStandardMaterial({ color: 'white' })
)
head.position.y = 2.3
snowman.add(head)
scene.add(new THREE.AmbientLight(0xffffff, 0.5) )
// Add the group to the scene
scene.add(snowman)
// Optional: expose to console
window.snowman = snowman
// Controls
const controls = new OrbitControls(perspCam, renderer.domElement)
// Resize handler
window.addEventListener('resize', () => {
perspCam.aspect = window.innerWidth / window.innerHeight
perspCam.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
})
// Animation loop
function animate() {
requestAnimationFrame(animate)
cube.rotation.x += 0.01
cube.rotation.y += 0.01
controls.update()
renderer.render(scene, activeCam)
}
window.addEventListener('keydown', (e) => {
if (e.key.toLowerCase() === 'o') {
activeCam = (activeCam === perspCam ? cam2d : perspCam)
console.log('Switched to', activeCam.isPerspectiveCamera ? 'Perspective' : 'Orthographic')
}
})
animate()
window.THREE = THREE
window.scene = scene
window.renderer = renderer
window.cube = cube
window.light = light
light.intensity = 2
</script>
</body>
</html>
+1 -1
View File
@@ -95,7 +95,7 @@ body[eicapp] {
bottom: auto;
overflow: hidden;
z-index: 2;
display: grid;
display: block;
grid-template-rows: min-content 1fr;
max-height: 90vh;
max-width: 90vw;
@@ -16,8 +16,9 @@
"/helpers/basicDialogs",
"/helpers/validators",
"/helpers/activeAttributes",
"/thirdparty/Snaptobus/snap.svg-min",
"/thirdparty/Snaptobus/snaptobus"
"/thirdparty/Threetobus/three.module",
"/thirdparty/Threetobus/OrbitControls.module",
"/thirdparty/Threetobus/threetobus.module"
],
"assets": {
"styles": [
+93
View File
@@ -0,0 +1,93 @@
//0. Add you dependencies in your controller.json :
// { ...
// "controllerDependencies": [
// ...
// "/thirdparty/Snaptobus/snap.svg-min",
// "/thirdparty/Snaptobus/snaptobus"
// ]
// }
// 1. Create your sprites :
agentTypes = {
molecule1:{
type: 'circle',
attrs: {
r: 10,
fill: '#BFB',
stroke: "#0A0",
strokeWidth: 2,
}
},
molecule2:{
type: 'circle',
attrs: {
r: 10,
fill: '#BBF',
stroke: "#00A",
strokeWidth: 2,
}
}
}
// 2. instantiate Snaptobus with the SVG playground selector, the sprites definitions,
// and the configuration mapping bus chans, bus event, and events playloads to SNap attributes
// You can assign a path in the event payload, or a transformer function like :
// fill: {
// arguments: [ 'age' ], // What to give from the event as function's params
// transformer: i => `rgb(${Math.round(255 * i / 10)},0,${Math.round(255 * (1 - i / 10))})`
// },
//
this.snaptobus = new Snaptobus({
snap: Snap("svg.stb"),
spriteDefs: this.agentTypes,
busConfig: [
{
chan: 'gps:agents', // What to subscribe to
events: [ // What to select on this chan
{ eventName: 'moving', // which event will trigger a change
snaps: [
{
selector: '#${aid}', // what svg elements do we change ?
assign: { // what do we change and with what from the payload ?
cx: 'attrs.x',
cy: 'attrs.y',
},
animate: true
}
]
},
]
},
]
})
//3. Create your sprites
this.createAgent('molecule2', 'agent42', 100,100)
createAgent(agentType, id, x, y){
if(!Object.keys(this.agentTypes).includes(agentType)) return
this.agentTypes[agentType]
const svgAgent = this.snaptobus.snap[this.agentTypes[agentType].type]().attr(this.agentTypes[agentType].attrs)
svgAgent.attr({
id: id,
cx: x,
cy:y,
})
}
//4. Send a bus event like : (this is a bmsg)
// {
// "channel":"gps:agents",
// "packet":{
// "eventType": "moving",
// "payload": {
// "aid": "agent42",
// "attrs": {
// "x": "950",
// "y": "650"
// }
// },
// "sender": "toto"
// }
// }
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+87
View File
@@ -0,0 +1,87 @@
import * as THREE from './three.module.js';
import { OrbitControls } from './OrbitControls.module.js';
export class Threetobus{
constructor(canvasEl){
this.canvasEl = canvasEl
}
init(){
// Scene
this.scene = new THREE.Scene()
//scene.background = new THREE.Color(0x202080)
// Camera
this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
this.camera.position.set(3, 3, 5)
// Renderer
this.renderer = new THREE.WebGLRenderer({ antialias: true, canvas: this.canvasEl })
//renderer.setSize(window.innerWidth, window.innerHeight)
// Cube
const geometry = new THREE.BoxGeometry()
const material = new THREE.MeshStandardMaterial({ color: 'red' })
this.cube = new THREE.Mesh(geometry, material)
this.scene.add(this.cube)
this.cube.position.x+=2
// Light
const light = new THREE.DirectionalLight(0xffffff, 1)
light.position.set(5, 5, 5)
light.intensity = 2
this.scene.add(light)
this.scene.add(new THREE.AmbientLight(0xffffff, 0.4))
this.controls = new OrbitControls(this.camera, this.renderer.domElement)
this.renderer.render(this.scene, this.camera)
window.addEventListener('resize', () => {
this.camera.aspect = window.innerWidth / window.innerHeight
this.camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
})
this.animate()
this._render()
}
_resizeRendererToDisplaySize() {
const canvas = this.renderer.domElement
const width = canvas.clientWidth
const height = canvas.clientHeight
if (canvas.width !== width || canvas.height !== height) {
this.renderer.setSize(width, height, false)
return true
}
return false
}
_render() {
if (this._resizeRendererToDisplaySize()) {
this.camera.aspect = this.renderer.domElement.clientWidth / this.renderer.domElement.clientHeight
this.camera.updateProjectionMatrix()
}
this.renderer.render(this.scene, this.camera)
requestAnimationFrame(this._render.bind(this))
}
animate() {
requestAnimationFrame(this.animate.bind(this))
this.cube.rotation.x += 0.01
this.cube.rotation.y += 0.01
this.controls.update()
this.renderer.render(this.scene, this.camera)
}
}
// Make this module available to common JS
if(!app.LoadedModules) app.LoadedModules = {}
app.LoadedModules.Threetobus = Threetobus
+5 -5
View File
@@ -4,10 +4,10 @@
height:100%;
background-color: #333;
}
canvas[data-output="paper43"]{
width: 100%;
height: 100%;
}
</style>
<article eiccard media class="mainDashboard">
<section>
<svg class="stb" width="100%" height="100%"></svg>
</section>
</article>
<canvas data-output="paper43"></canvas>
+4 -50
View File
@@ -26,8 +26,6 @@ class MainDashboardView extends EICDomContent {
super()
Object.assign(this, app.helpers.activeAttributes)
//this.tileMarkup = app.Assets.Store.html['/app/assets/html/mailing/tile.html']
this.snap = null
this.snaptobus = null
}
DOMContentLoaded(options) {
@@ -35,38 +33,10 @@ class MainDashboardView extends EICDomContent {
const components = ui.eicfy(this.el)
this.setupTriggers(components)
this.setupRefs(components)
this.snaptobus = new Snaptobus({
snap: Snap("svg.stb"),
spriteDefs: this.agentTypes,
busConfig: [
{
chan: 'gps:agents', // What to subscribe to
events: [ // What to select on this chan
{ eventName: 'moving', // which event will trigger a change
snaps: [
{
selector: '#${aid}', // what svg elements do we change ?
assign: { // what do we change and with what from the payload ?
cx: 'attrs.x',
cy: 'attrs.y',
},
animate: true
}
]
},
]
},
]
})
// var agent = this.snap.circle(150, 150, 20);
// agent.attr({
// id: 'agent42',
// fill: "#BFB",
// stroke: "#0A0",
// strokeWidth: 2
// });
this.createAgent('molecule2', 'agent42', 100,100)
//setTimeout(this.moveit.bind(this), 3000);
this.ttb = new app.LoadedModules.Threetobus(this.outputs.paper43)
this.ttb.init()
}
DOMContentFocused(options) {
@@ -90,22 +60,6 @@ class MainDashboardView extends EICDomContent {
})
}
// moveit(){
// var myCircle = this.snap.select('#agent42')
// var newx = parseInt(myCircle.attr('cx')) + 600
// var newy = parseInt(myCircle.attr('cy')) + 200
// // animate translate
// myCircle.animate(
// {
// cx: newx,
// cy: newy,
// },
// 1000, // duration in ms
// mina.linear // easing
// )
// }
}
app.registerClass('MainDashboardView', MainDashboardView)