<!-- Lume 3D elements 👉 https://lume.io ✨ -->
<lume-scene webgl physically-correct-lights perspective="800" fog-mode="linear" fog-color="black" fog-near="600" fog-far="700">
	<lume-camera-rig distance="800" min-distance="800" max-distance="800" min-vertical-angle="0" max-vertical-angle="0">
		<lume-point-light intensity="1900" slot="camera-child"></lume-point-light>
	</lume-camera-rig>
	
	<!-- This element is defined in the JS to show how to make custom elements. -->
	<my-photos></my-photos>
</lume-scene>

<meta name="viewport" content="width=device-width, initial-scale=1" />

  <!--
	The following importmap tells the browser where Lume and its dependencies will come from.
    Import map generated with JSPM Generator.
    Edit: https://generator.jspm.io/#U2NhYGBiDs0rySzJSU1hyCnNTXUw0DPWM9BNzCnISNQzMWQozs/JTNHNKnYw1LPQMzTTLy7JL0oFAOY0iAI4AA
  -->
   <script type="importmap">
  {
    "imports": {
      "lume": "https://ga.jspm.io/npm:lume@0.3.0-alpha.41/dist/index.js",
      "solid-js/store": "https://ga.jspm.io/npm:solid-js@1.8.16/store/dist/store.js",
      "classy-solid": "https://ga.jspm.io/npm:classy-solid@0.3.7/dist/index.js"
    },
    "scopes": {
      "https://ga.jspm.io/": {
        "@lume/autolayout": "https://ga.jspm.io/npm:@lume/autolayout@0.10.1/dist/AutoLayout.js",
        "@lume/custom-attributes/dist/index.js": "https://ga.jspm.io/npm:@lume/custom-attributes@0.2.3/dist/index.js",
        "@lume/element": "https://ga.jspm.io/npm:@lume/element@0.11.7/dist/index.js",
        "@lume/eventful": "https://ga.jspm.io/npm:@lume/eventful@0.3.2/dist/index.js",
        "@lume/kiwi": "https://ga.jspm.io/npm:@lume/kiwi@0.4.3/dist/kiwi.js",
        "@lume/three-projected-material/dist/ProjectedMaterial.js": "https://ga.jspm.io/npm:@lume/three-projected-material@0.3.1/dist/ProjectedMaterial.js",
        "element-behaviors": "https://ga.jspm.io/npm:element-behaviors@5.0.3/dist/index.js",
        "james-bond": "https://ga.jspm.io/npm:james-bond@0.7.3/dist/index.js",
        "lowclass": "https://ga.jspm.io/npm:lowclass@7.0.1/dist/index.js",
        "regexr": "https://ga.jspm.io/npm:regexr@2.0.4/dist/index.js",
        "solid-js": "https://ga.jspm.io/npm:solid-js@1.8.16/dist/solid.js",
        "solid-js/html": "https://ga.jspm.io/npm:solid-js@1.8.16/html/dist/html.js",
        "solid-js/web": "https://ga.jspm.io/npm:solid-js@1.8.16/web/dist/web.js",
        "three": "https://ga.jspm.io/npm:three@0.163.0/build/three.module.js",
        "three/": "https://ga.jspm.io/npm:three@0.163.0/"
      }
    }
  }
  </script>
html,
body {
	margin: 0;
	height: 100%;
	background: black;
	touch-action: none;
}
import {Element3D, element, html, attribute, Index} from 'lume'
import {signalify} from 'classy-solid'

async function fetchPhotos() {
	const json = await fetch('https://picsum.photos/v2/list?page=2&limit=14').then(r => r.json())

	// change the size to 100x100
	json.forEach(photo => {
		const parts = photo.download_url.split('/')
		parts.pop()
		parts.pop()
		parts.push(100)
		photo.download_url = parts.join('/')
	})

	console.log('photos:', json.map(photo => photo.download_url))
	return json.map(photo => photo.download_url)
}

const photos = await fetchPhotos()

element('my-photos')(class extends Element3D {
	template = () => html`
        <carousel-layout radius="200">
            ${photos.map((photo, i) => html`
				<lume-rounded-rectangle
					size="80 80"
					corner-radius="10"
					thickness="0.1"
					mount-point="0.5 0.5"
					has="projected-material"
					texture-projectors=${".projector"+i}
					cast-shadow="false"
					receive-shadow="false"
					roughness="0.5"
				>
					<lume-texture-projector
						class=${"projector"+i}
						src=${photo}
						fitment="contain"
						size-mode="p p"
						size="1.1 1.1"
						align-point="0.5 0.5"
						mount-point="0.5 0.5"
						position="0 0 150"
					></lume-texture-projector>
				</lume-rounded-rectangle>
            `)}
        </carousel-layout>
    `

})

element('carousel-layout')(class extends Element3D {
	static observedAttributes = {
		radius: attribute.string(),
	}
	
	radius = 200
	
	hasShadow = true
	childrenSignal = []
	
	constructor() {
		super()
		signalify(this, 'childrenSignal')
	}
	
	connectedCallback() {
		super.connectedCallback()
		
		this.createEffect(() => {
			console.log('children length: ', this.childrenSignal.length)
			let i = -1
			for (const child of this.childrenSignal) {
				i++
				child.slot = "slot" + i
			}
		})
	}
	
	#queued = false
	
	childConnectedCallback(...args) {
		super.childConnectedCallback(...args)
		
		if (this.#queued) return
		this.#queued = true
		// return
		requestAnimationFrame(() => {
			console.log('handle children', this.children)
			this.#queued = false
			this.childrenSignal = Array.from(this.children)
		})
	}

	template = () => html`
		<${Index} each=${() => this.childrenSignal}>
			${(_, index) => html`
				<lume-element3d rotation=${() => [0, (360 / this.childrenSignal.length) * index]}>
					<lume-element3d position=${() => [0, 0, this.radius]} mount-point="0.5 0.5">
						<slot name=${() => "slot" + index}></slot>
					</lume-element3d>
				</lume-element3d>
			`}
		</>
	`
})
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.