Update index.html
Browse files- index.html +130 -186
index.html
CHANGED
@@ -1,219 +1,163 @@
|
|
1 |
<!DOCTYPE html>
|
2 |
-
<html>
|
3 |
<head>
|
4 |
-
<meta charset="
|
5 |
-
<
|
6 |
-
<
|
|
|
7 |
<style>
|
8 |
-
|
9 |
-
position: fixed;
|
10 |
-
top: 20px;
|
11 |
-
left: 20px;
|
12 |
-
z-index: 9999;
|
13 |
-
background: rgba(0,0,0,0.7);
|
14 |
-
padding: 10px;
|
15 |
-
border-radius: 5px;
|
16 |
-
color: white;
|
17 |
font-family: Arial, sans-serif;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
}
|
19 |
-
.
|
20 |
-
|
21 |
-
margin: 5px 0;
|
22 |
-
padding: 5px 10px;
|
23 |
}
|
24 |
-
.
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
background: rgba(0,0,0,0.7);
|
30 |
-
padding: 10px;
|
31 |
-
border-radius: 5px;
|
32 |
-
color: white;
|
33 |
-
font-family: Arial, sans-serif;
|
34 |
-
}
|
35 |
-
.control-panel input {
|
36 |
-
width: 50px;
|
37 |
-
margin-right: 5px;
|
38 |
}
|
39 |
-
.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
display: flex;
|
|
|
|
|
41 |
align-items: center;
|
42 |
-
margin-top: 10px;
|
43 |
}
|
44 |
-
.
|
45 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
}
|
47 |
</style>
|
48 |
</head>
|
49 |
<body>
|
50 |
-
<div class="
|
51 |
-
<
|
52 |
-
<
|
53 |
-
<button
|
54 |
-
<button onclick="addPrimitive('cone')">Add Cone</button>
|
55 |
-
<button onclick="addPrimitive('torus')">Add Torus</button>
|
56 |
</div>
|
57 |
|
58 |
-
<div class="control-panel">
|
59 |
-
<h3>Object Controls</h3>
|
60 |
-
<p>Position:</p>
|
61 |
-
<input id="px" type="number" step="0.1" placeholder="X">
|
62 |
-
<input id="py" type="number" step="0.1" placeholder="Y">
|
63 |
-
<input id="pz" type="number" step="0.1" placeholder="Z">
|
64 |
-
<p>Rotation (degrees):</p>
|
65 |
-
<input id="rx" type="number" step="1" placeholder="X">
|
66 |
-
<input id="ry" type="number" step="1" placeholder="Y">
|
67 |
-
<input id="rz" type="number" step="1" placeholder="Z">
|
68 |
-
<p>Rotation Velocity (degrees/second):</p>
|
69 |
-
<input id="rvx" type="number" step="1" placeholder="X">
|
70 |
-
<input id="rvy" type="number" step="1" placeholder="Y">
|
71 |
-
<input id="rvz" type="number" step="1" placeholder="Z">
|
72 |
-
<button onclick="applyTransform()">Apply Transform</button>
|
73 |
-
<button onclick="placeInFrontOfCamera()">Place in Front of Camera</button>
|
74 |
-
<div class="color-picker">
|
75 |
-
<input type="color" id="colorPicker" value="#4CC3D9">
|
76 |
-
<button onclick="applyColor()">Apply Color</button>
|
77 |
-
</div>
|
78 |
-
</div>
|
79 |
-
|
80 |
-
<a-scene>
|
81 |
-
<a-sky color="#ECECEC"></a-sky>
|
82 |
-
<a-entity id="rig" position="0 1.6 0">
|
83 |
-
<a-camera look-controls wasd-controls>
|
84 |
-
<a-cursor></a-cursor>
|
85 |
-
</a-camera>
|
86 |
-
</a-entity>
|
87 |
-
</a-scene>
|
88 |
-
|
89 |
<script>
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
function selectObject(obj) {
|
107 |
-
if (selectedObject) {
|
108 |
-
selectedObject.setAttribute('material', 'color', selectedObject.getAttribute('material').color);
|
109 |
-
}
|
110 |
-
selectedObject = obj;
|
111 |
-
document.getElementById('colorPicker').value = selectedObject.getAttribute('material').color;
|
112 |
-
selectedObject.setAttribute('material', 'color', '#FF0000');
|
113 |
-
updateTransformInputs(selectedObject);
|
114 |
-
}
|
115 |
-
|
116 |
-
function updateTransformInputs(obj) {
|
117 |
-
const position = obj.getAttribute('position');
|
118 |
-
document.getElementById('px').value = position.x.toFixed(2);
|
119 |
-
document.getElementById('py').value = position.y.toFixed(2);
|
120 |
-
document.getElementById('pz').value = position.z.toFixed(2);
|
121 |
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
document.getElementById('rvx').value = obj.rotationVelocity.x;
|
128 |
-
document.getElementById('rvy').value = obj.rotationVelocity.y;
|
129 |
-
document.getElementById('rvz').value = obj.rotationVelocity.z;
|
130 |
-
}
|
131 |
-
|
132 |
-
function applyTransform() {
|
133 |
-
if (!selectedObject) {
|
134 |
-
alert('Please select an object first');
|
135 |
-
return;
|
136 |
-
}
|
137 |
-
|
138 |
-
const px = parseFloat(document.getElementById('px').value) || 0;
|
139 |
-
const py = parseFloat(document.getElementById('py').value) || 0;
|
140 |
-
const pz = parseFloat(document.getElementById('pz').value) || 0;
|
141 |
-
const rx = parseFloat(document.getElementById('rx').value) || 0;
|
142 |
-
const ry = parseFloat(document.getElementById('ry').value) || 0;
|
143 |
-
const rz = parseFloat(document.getElementById('rz').value) || 0;
|
144 |
-
const rvx = parseFloat(document.getElementById('rvx').value) || 0;
|
145 |
-
const rvy = parseFloat(document.getElementById('rvy').value) || 0;
|
146 |
-
const rvz = parseFloat(document.getElementById('rvz').value) || 0;
|
147 |
-
|
148 |
-
selectedObject.setAttribute('position', `${px} ${py} ${pz}`);
|
149 |
-
selectedObject.setAttribute('rotation', `${rx} ${ry} ${rz}`);
|
150 |
-
selectedObject.rotationVelocity = { x: rvx, y: rvy, z: rvz };
|
151 |
-
}
|
152 |
-
|
153 |
-
function placeInFrontOfCamera(obj = null) {
|
154 |
-
const targetObject = obj || selectedObject;
|
155 |
-
if (!targetObject) {
|
156 |
-
alert('Please select an object first');
|
157 |
-
return;
|
158 |
-
}
|
159 |
-
|
160 |
-
const camera = document.querySelector('[camera]');
|
161 |
-
const cameraPosition = camera.object3D.position;
|
162 |
-
const cameraRotation = camera.object3D.rotation;
|
163 |
-
|
164 |
-
// Calculate the direction the camera is looking
|
165 |
-
const direction = new THREE.Vector3(0, 0, -1);
|
166 |
-
direction.applyQuaternion(camera.object3D.quaternion);
|
167 |
-
|
168 |
-
// Set the distance to be 3 units away from the camera
|
169 |
-
const distance = 3;
|
170 |
|
171 |
-
//
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
);
|
177 |
-
|
178 |
-
targetObject.setAttribute('position', newPosition);
|
179 |
|
180 |
-
//
|
181 |
-
|
182 |
-
|
183 |
-
}
|
184 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
|
186 |
-
function
|
187 |
-
|
188 |
-
|
189 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
}
|
191 |
-
const color = document.getElementById('colorPicker').value;
|
192 |
-
selectedObject.setAttribute('material', 'color', color);
|
193 |
}
|
194 |
|
195 |
-
function
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
y: (currentRotation.y + obj.rotationVelocity.y * 0.016) % 360,
|
201 |
-
z: (currentRotation.z + obj.rotationVelocity.z * 0.016) % 360
|
202 |
-
};
|
203 |
-
obj.setAttribute('rotation', newRotation);
|
204 |
});
|
205 |
-
|
206 |
}
|
207 |
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
}
|
213 |
});
|
214 |
|
215 |
-
|
216 |
-
|
|
|
|
|
|
|
|
|
|
|
217 |
</script>
|
218 |
</body>
|
219 |
</html>
|
|
|
1 |
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>Chord Arpeggio Pad</title>
|
7 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.js"></script>
|
8 |
<style>
|
9 |
+
body {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
font-family: Arial, sans-serif;
|
11 |
+
display: flex;
|
12 |
+
justify-content: center;
|
13 |
+
align-items: center;
|
14 |
+
height: 100vh;
|
15 |
+
margin: 0;
|
16 |
+
background-color: #121212;
|
17 |
+
color: #ffffff;
|
18 |
}
|
19 |
+
.container {
|
20 |
+
text-align: center;
|
|
|
|
|
21 |
}
|
22 |
+
.arpeggio-pad {
|
23 |
+
display: grid;
|
24 |
+
grid-template-columns: repeat(4, 1fr);
|
25 |
+
gap: 10px;
|
26 |
+
margin-bottom: 20px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
}
|
28 |
+
.pad {
|
29 |
+
width: 80px;
|
30 |
+
height: 80px;
|
31 |
+
font-size: 14px;
|
32 |
+
border: none;
|
33 |
+
color: white;
|
34 |
+
cursor: pointer;
|
35 |
+
transition: all 0.3s;
|
36 |
+
border-radius: 8px;
|
37 |
display: flex;
|
38 |
+
flex-direction: column;
|
39 |
+
justify-content: center;
|
40 |
align-items: center;
|
|
|
41 |
}
|
42 |
+
.pad:hover {
|
43 |
+
opacity: 0.8;
|
44 |
+
}
|
45 |
+
.pad:active, .pad.active {
|
46 |
+
transform: scale(0.95);
|
47 |
+
box-shadow: 0 0 15px rgba(255, 255, 255, 0.5);
|
48 |
+
}
|
49 |
+
h1 {
|
50 |
+
margin-bottom: 20px;
|
51 |
+
}
|
52 |
+
#effectsButton {
|
53 |
+
font-size: 18px;
|
54 |
+
padding: 10px 20px;
|
55 |
+
background-color: #4CAF50;
|
56 |
+
border: none;
|
57 |
+
color: white;
|
58 |
+
cursor: pointer;
|
59 |
+
border-radius: 5px;
|
60 |
+
transition: background-color 0.3s;
|
61 |
+
}
|
62 |
+
#effectsButton:hover {
|
63 |
+
background-color: #45a049;
|
64 |
+
}
|
65 |
+
#effectsButton.active {
|
66 |
+
background-color: #e91e63;
|
67 |
}
|
68 |
</style>
|
69 |
</head>
|
70 |
<body>
|
71 |
+
<div class="container">
|
72 |
+
<h1>Chord Arpeggio Pad</h1>
|
73 |
+
<div class="arpeggio-pad" id="arpeggiopad"></div>
|
74 |
+
<button id="effectsButton">Effects: OFF</button>
|
|
|
|
|
75 |
</div>
|
76 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
<script>
|
78 |
+
const arpeggiopad = document.getElementById('arpeggiopad');
|
79 |
+
const effectsButton = document.getElementById('effectsButton');
|
80 |
+
const synth = new Tone.PolySynth(Tone.Synth).toDestination();
|
81 |
+
|
82 |
+
// Effects chain
|
83 |
+
const distortion = new Tone.Distortion(0.8).toDestination();
|
84 |
+
const reverb = new Tone.Reverb(2).toDestination();
|
85 |
+
let effectsOn = false;
|
86 |
+
|
87 |
+
const arpeggios = [
|
88 |
+
// C Major (I)
|
89 |
+
{ chord: 'C', notes: ['C4', 'E4', 'G4', 'C5'], color: '#FF0000' },
|
90 |
+
{ chord: 'C', notes: ['E4', 'G4', 'C5', 'E5'], color: '#FF4000' },
|
91 |
+
{ chord: 'C', notes: ['G4', 'C5', 'E5', 'G5'], color: '#FF8000' },
|
92 |
+
{ chord: 'C', notes: ['C5', 'E5', 'G5', 'C6'], color: '#FFC000' },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
|
94 |
+
// F Major (IV)
|
95 |
+
{ chord: 'F', notes: ['F4', 'A4', 'C5', 'F5'], color: '#FFFF00' },
|
96 |
+
{ chord: 'F', notes: ['A4', 'C5', 'F5', 'A5'], color: '#C0FF00' },
|
97 |
+
{ chord: 'F', notes: ['C5', 'F5', 'A5', 'C6'], color: '#80FF00' },
|
98 |
+
{ chord: 'F', notes: ['F5', 'A5', 'C6', 'F6'], color: '#40FF00' },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
|
100 |
+
// G Major (V)
|
101 |
+
{ chord: 'G', notes: ['G4', 'B4', 'D5', 'G5'], color: '#00FF00' },
|
102 |
+
{ chord: 'G', notes: ['B4', 'D5', 'G5', 'B5'], color: '#00FF40' },
|
103 |
+
{ chord: 'G', notes: ['D5', 'G5', 'B5', 'D6'], color: '#00FF80' },
|
104 |
+
{ chord: 'G', notes: ['G5', 'B5', 'D6', 'G6'], color: '#00FFC0' },
|
|
|
|
|
|
|
105 |
|
106 |
+
// Am (vi)
|
107 |
+
{ chord: 'Am', notes: ['A4', 'C5', 'E5', 'A5'], color: '#00FFFF' },
|
108 |
+
{ chord: 'Am', notes: ['C5', 'E5', 'A5', 'C6'], color: '#00C0FF' },
|
109 |
+
{ chord: 'Am', notes: ['E5', 'A5', 'C6', 'E6'], color: '#0080FF' },
|
110 |
+
{ chord: 'Am', notes: ['A5', 'C6', 'E6', 'A6'], color: '#0040FF' }
|
111 |
+
];
|
112 |
+
|
113 |
+
arpeggios.forEach(({ chord, notes, color }, index) => {
|
114 |
+
const pad = document.createElement('button');
|
115 |
+
pad.innerHTML = `${chord}<br>${notes[0]}-${notes[3]}`;
|
116 |
+
pad.className = 'pad';
|
117 |
+
pad.dataset.notes = JSON.stringify(notes);
|
118 |
+
pad.style.backgroundColor = color;
|
119 |
+
arpeggiopad.appendChild(pad);
|
120 |
+
});
|
121 |
|
122 |
+
function toggleEffects() {
|
123 |
+
effectsOn = !effectsOn;
|
124 |
+
if (effectsOn) {
|
125 |
+
synth.disconnect();
|
126 |
+
synth.connect(distortion);
|
127 |
+
synth.connect(reverb);
|
128 |
+
effectsButton.textContent = 'Effects: ON';
|
129 |
+
effectsButton.classList.add('active');
|
130 |
+
} else {
|
131 |
+
synth.disconnect();
|
132 |
+
synth.toDestination();
|
133 |
+
effectsButton.textContent = 'Effects: OFF';
|
134 |
+
effectsButton.classList.remove('active');
|
135 |
}
|
|
|
|
|
136 |
}
|
137 |
|
138 |
+
function playArpeggio(notes, pad) {
|
139 |
+
pad.classList.add('active');
|
140 |
+
const now = Tone.now();
|
141 |
+
notes.forEach((note, index) => {
|
142 |
+
synth.triggerAttackRelease(note, "8n", now + index * 0.2);
|
|
|
|
|
|
|
|
|
143 |
});
|
144 |
+
setTimeout(() => pad.classList.remove('active'), notes.length * 200);
|
145 |
}
|
146 |
|
147 |
+
arpeggiopad.addEventListener('mousedown', (e) => {
|
148 |
+
if (e.target.classList.contains('pad')) {
|
149 |
+
const notes = JSON.parse(e.target.dataset.notes);
|
150 |
+
playArpeggio(notes, e.target);
|
151 |
}
|
152 |
});
|
153 |
|
154 |
+
effectsButton.addEventListener('click', toggleEffects);
|
155 |
+
|
156 |
+
// Start audio context on user interaction
|
157 |
+
document.addEventListener('click', async () => {
|
158 |
+
await Tone.start();
|
159 |
+
console.log('Audio is ready');
|
160 |
+
}, { once: true });
|
161 |
</script>
|
162 |
</body>
|
163 |
</html>
|