266 lines
5.0 KiB
HTML
266 lines
5.0 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<title>Three.js Texture Editor</title>
|
|
<style>
|
|
html, body {
|
|
margin: 0;
|
|
padding: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
font-family: sans-serif;
|
|
display: flex;
|
|
flex-direction: column;
|
|
background-color: #000;
|
|
}
|
|
|
|
#topBar {
|
|
height: 40px;
|
|
background: #141414;
|
|
color: white;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
padding: 0 10px;
|
|
flex-shrink: 0;
|
|
border-bottom: 1px solid #222;
|
|
}
|
|
|
|
button {
|
|
background: #2a2a2a;
|
|
color: #eee;
|
|
border: 1px solid #444;
|
|
padding: 6px 12px;
|
|
cursor: pointer;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
button:hover {
|
|
background: #333;
|
|
}
|
|
|
|
#main {
|
|
display: flex;
|
|
flex: 1;
|
|
min-height: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
#leftPanel {
|
|
width: 150px;
|
|
background: #141414;
|
|
color: white;
|
|
padding: 10px;
|
|
overflow-y: auto;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
#primitiveList .title {
|
|
font-weight: bold;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
#primitiveList div[data-primitive] {
|
|
padding: 5px;
|
|
margin-bottom: 5px;
|
|
background: #1c1c1c;
|
|
border-radius: 4px;
|
|
cursor: grab;
|
|
text-align: center;
|
|
border: 1px solid #333;
|
|
}
|
|
|
|
#threeCanvas {
|
|
flex-grow: 1;
|
|
flex-shrink: 1;
|
|
flex-basis: 0;
|
|
height: 100%;
|
|
width: auto;
|
|
max-width: 100%;
|
|
display: block;
|
|
}
|
|
|
|
|
|
#rightPanel {
|
|
width: 300px;
|
|
background: #141414;
|
|
color: white;
|
|
padding: 10px;
|
|
overflow-y: auto;
|
|
overflow-x: hidden;
|
|
flex-shrink: 0;
|
|
scrollbar-width: thin; /* Firefox */
|
|
scrollbar-color: #444 #141414;
|
|
}
|
|
|
|
/* Chrome, Edge, Safari */
|
|
#rightPanel::-webkit-scrollbar {
|
|
width: 6px;
|
|
}
|
|
|
|
#rightPanel::-webkit-scrollbar-track {
|
|
background: #141414;
|
|
}
|
|
|
|
#rightPanel::-webkit-scrollbar-thumb {
|
|
background-color: #444;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
input[type="range"],
|
|
input[type="color"],
|
|
input[type="file"],
|
|
input[type="text"] {
|
|
width: 100%;
|
|
margin-bottom: 10px;
|
|
background: #1a1a1a;
|
|
border: 1px solid #444;
|
|
color: #eee;
|
|
padding: 4px;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
label {
|
|
display: block;
|
|
margin-top: 10px;
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
canvas#materialPreview {
|
|
width: 100%;
|
|
border: 1px solid #333;
|
|
margin-bottom: 10px;
|
|
background: #0a0a0a;
|
|
}
|
|
|
|
#bottomPanel {
|
|
height: 260px;
|
|
background: #141414;
|
|
color: white;
|
|
overflow-y: auto;
|
|
padding: 10px;
|
|
flex-shrink: 0;
|
|
border-top: 1px solid #222;
|
|
}
|
|
|
|
#materialList {
|
|
display: flex;
|
|
flex-direction: row;
|
|
gap: 14px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.material-item {
|
|
width: 100px;
|
|
text-align: center;
|
|
color: #fff;
|
|
background: #1a1a1a;
|
|
padding: 5px;
|
|
cursor: grab;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.material-item img {
|
|
width: 96px;
|
|
height: 96px;
|
|
display: block;
|
|
margin: 0 auto 6px auto;
|
|
border-radius: 4px;
|
|
object-fit: cover;
|
|
}
|
|
|
|
#addMaterialBtn {
|
|
margin-bottom: 10px;
|
|
width: 100%;
|
|
}
|
|
|
|
hr {
|
|
border: none;
|
|
border-top: 1px solid #333;
|
|
margin: 10px 0;
|
|
}
|
|
.bottomPanel {
|
|
height: 100px;
|
|
}
|
|
|
|
.thumbnail {
|
|
width: 128px;
|
|
height: 128px;
|
|
}
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div id="topBar">
|
|
<button id="translateBtn">Translate</button>
|
|
<button id="rotateBtn">Rotate</button>
|
|
<button id="scaleBtn">Scale</button>
|
|
<button id="noneBtn">Deselect</button>
|
|
</div>
|
|
|
|
<div id="main">
|
|
<div id="leftPanel">
|
|
<div id="primitiveList">
|
|
<div class="title">Primitives</div>
|
|
<div draggable="true" data-primitive="cube" class="primitive-item">Cube</div>
|
|
<div draggable="true" data-primitive="sphere" class="primitive-item">Sphere</div>
|
|
<div draggable="true" data-primitive="cylinder" class="primitive-item">Cylinder</div>
|
|
</div>
|
|
</div>
|
|
|
|
<canvas id="threeCanvas"></canvas>
|
|
|
|
<div id="rightPanel">
|
|
<h3>PBR Material Panel</h3>
|
|
|
|
<label>Name:</label>
|
|
<input type="text" id="matName" placeholder="Material name">
|
|
|
|
<canvas id="materialPreview" width="200" height="200"></canvas>
|
|
|
|
<label>Color:</label>
|
|
<input type="color" id="colorPicker" value="#888888">
|
|
|
|
<label>Roughness:</label>
|
|
<input type="range" id="roughnessSlider" min="0" max="1" step="0.01" value="0.5">
|
|
|
|
<label>Metalness:</label>
|
|
<input type="range" id="metalnessSlider" min="0" max="1" step="0.01" value="0.5">
|
|
|
|
<label>Displacement:</label>
|
|
<input type="range" id="displacementSlider" min="0" max="1" step="0.01" value="0">
|
|
|
|
<label>Opacity:</label>
|
|
<input type="range" id="opacitySlider" min="0" max="1" step="0.01" value="1">
|
|
|
|
<label>Map:</label>
|
|
<input type="file" id="mapInput">
|
|
|
|
<label>Normal Map:</label>
|
|
<input type="file" id="normalInput">
|
|
|
|
<label>Roughness Map:</label>
|
|
<input type="file" id="roughnessInput">
|
|
|
|
<label>Metalness Map:</label>
|
|
<input type="file" id="metalnessInput">
|
|
|
|
<label>Alpha Map:</label>
|
|
<input type="file" id="alphaInput">
|
|
|
|
<button id="saveMaterial">Add/Update Material</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="bottomPanel">
|
|
<button id="addMaterialBtn">+ Add Material</button>
|
|
<div id="materialList"></div>
|
|
</div>
|
|
|
|
<script type="module" src="./material-editor.js"></script>
|
|
</body>
|
|
</html>
|