<!-- local-files-with-three-js.html -->
<html>
<head>
<style>
body {
margin : 40px;
font-family : arial;
}
input {
font-size : 16px;
padding : 5px;
}
#user > * {
margin-top : 20px;
}
#url {
display : flex;
gap : 20px;
align-items : center;
}
#url input {
width : 100%;
}
#file input {
width : 225px;
}
#mesh input {
width : 225px;
}
#three {
margin-top : 30px;
display : flex;
justify-content : center;
}
</style>
</head>
<body>
<div id=user>
<div id=url><input placeholder='paste url here, hit enter' onchange='url_change(event)'></div>
<div id=file><input value='load texture from file' type=button onclick='file_change(event)'></div>
<div id=mesh><input type=button value=mesh onclick='mesh(event)'></div>
</div>
<div id=three></div>
</body>
<script type=module>
import * as THREE from 'https://esm.run/three';
window.onload=function(){
mesh();
//texture(files.read('sun.jpg'));
}//onload
window.url_change=function(e){
texture(e.target.value);
e.target.value = '';
}//url_change
window.file_change=function(e){
var input = document.createElement('input');
input.type = 'file';
input.onchange = onchange;
input.click();
function onchange(){
var blob = input.files[0];
var url = URL.createObjectURL(blob);
texture(url);
}//onchange
}//file_change
window.mesh=function(){
var meshMaterial = new THREE.MeshPhongMaterial({color:'lightblue',emissive:'blue',flatShading:true});
draw(meshMaterial);
}//mesh
window.texture=function(url){
var texture = new THREE.TextureLoader().load(url);
var material = new THREE.MeshBasicMaterial({map:texture});
draw(material);
}//texture
function draw(material){
var scene = new THREE.Scene();
scene.background = new THREE.Color('gray');
var camera = new THREE.PerspectiveCamera(75,1,1,50);
camera.position.z = 50;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(300,300);
document.getElementById('three').replaceChildren(renderer.domElement);
var lights = new THREE.DirectionalLight('white',3);
lights.position.set(75,75,200);
scene.add(lights);
//var geometry = new THREE.BufferGeometry();
const geometry = new THREE.SphereGeometry(25, 32, 32);
const sphere = new THREE.Mesh(geometry,material);
scene.add(sphere);
(function render() {
sphere.rotation.y += 0.005;
renderer.render(scene,camera);
requestAnimationFrame(render);
})();
}//draw
</script>
<script>
console.clear();
var files = {};
files.read = filename=>localStorage[filename];
files.remove = filename=>delete localStorage[filename];
files.clear = ()=>localStorage.clear();
files.list = ()=>{for(var key in {localStorage})console.log(key)};
//files.clear();
files.list();
var root = document.createElement('div');
root.style.padding = '20px';
root.style.border = '2px dashed blue';
document.body.insertBefore(root,document.body.firstChild);
btn('select persistent files',create);
btn('clear persistent files',files.clear);
btn('list persistent files',files.list);
function btn(value,onclick){
var input = document.createElement('input');
input.value = value
input.type = 'button';
input.onclick = onclick;
input.style.marginRight = '20px';
root.append(input);
}//btn
function create(e){
var input = document.createElement('input');
input.type = 'file';
input.multiple = true;
input.onchange = onchange;
input.click();
function onchange(e){
[input.files].forEach(async file=>{
console.log(file.name);
var url = await datauri(file);
localStorage[file.name] = url;
});
}//onchange
}//create
async function datauri(file){
var i = file.name.lastIndexOf('.');
var ext = file.name.slice(i+1);
var mime = 'image/'+ext;
var buf = await file.arrayBuffer();
var bytes = new Uint8Array(buf);
var binary = '';
var n = bytes.byteLength;
for(var i=0;i<n;i++){
binary += String.fromCharCode(bytes[i]);
}//for
var b64 = window.btoa(binary);
var datauri = 'data:'+mime+';base64,'+b64;
return datauri;
}//datauri
</script>
</html>
Output
300px
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |