Skip to content

Commit 6fd9630

Browse files
authored
Update index.html
1 parent 69f14a5 commit 6fd9630

File tree

1 file changed

+119
-40
lines changed

1 file changed

+119
-40
lines changed

index.html

Lines changed: 119 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<head>
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6-
<title>Pixel Swirl Version 1.006</title> <style>
6+
<title>Pixel Swirl Version 1.007</title> <style>
77
body {
88
font-family: Arial, sans-serif;
99
display: flex; /* Changed to flex to control main content better */
@@ -147,6 +147,16 @@
147147
button:hover {
148148
background-color: #0056b3;
149149
}
150+
151+
/* Styling for the new Defaults button */
152+
button#defaultsButton {
153+
background-color: #dc3545; /* Red color */
154+
}
155+
156+
button#defaultsButton:hover {
157+
background-color: #c82333; /* Darker red on hover */
158+
}
159+
150160
input[type="file"] {
151161
display: none;
152162
}
@@ -200,6 +210,13 @@
200210
.app-info a:hover {
201211
text-decoration: underline;
202212
}
213+
.not-mobile {
214+
font-style: italic;
215+
font-size: 0.9em;
216+
color: #aaa;
217+
margin-top: 5px;
218+
margin-bottom: 5px;
219+
}
203220
</style>
204221
</head>
205222
<body>
@@ -282,7 +299,7 @@
282299

283300
<div class="controls-row">
284301
<div class="control-group">
285-
<label for="frequencySlider">Frequency:</label>
302+
<label for="frequencySlider">Frequency (seconds):</label>
286303
<div class="slider-with-value">
287304
<input type="range" id="frequencySlider" min="0" max="10" value="0" step="1">
288305
<span id="frequencyValue">0</span>
@@ -304,9 +321,15 @@
304321
</div>
305322
</div>
306323

324+
<div class="controls-row">
325+
<button id="defaultsButton">Defaults</button>
326+
</div>
327+
328+
307329
<div class="app-info">
308330
<h2>Pixel Swirl</h2>
309-
<span id="versionNumber">Version 1.006</span>
331+
<span id="versionNumber">Version 1.007</span>
332+
<span class="not-mobile">(Not for Mobile Use)</span>
310333
<hr> <br>
311334
Check out other cool stuff:<br>
312335
<br>
@@ -332,16 +355,16 @@ <h2>Pixel Swirl</h2>
332355
const gravityValueSpan = document.getElementById('gravityValue');
333356
const snapDistanceSlider = document.getElementById('snapDistanceSlider');
334357
const snapDistanceValueSpan = document.getElementById('snapDistanceValue');
335-
const repelSlider = document.getElementById('repelSlider'); // New Repel slider
336-
const repelValueSpan = document.getElementById('repelValue'); // New Repel value span
337-
const frequencySlider = document.getElementById('frequencySlider'); // New Frequency slider
338-
const frequencyValueSpan = document.getElementById('frequencyValue'); // New Frequency value span
358+
const repelSlider = document.getElementById('repelSlider');
359+
const repelValueSpan = document.getElementById('repelValue');
360+
const frequencySlider = document.getElementById('frequencySlider');
361+
const frequencyValueSpan = document.getElementById('frequencyValue');
339362
const unlockPieceSizeCheckbox = document.getElementById('unlockPieceSizeCheckbox');
340363
const unlockFreedomCheckbox = document.getElementById('unlockFreedomCheckbox');
341364
const versionNumberSpan = document.getElementById('versionNumber');
342365
const maxPiecesInput = document.getElementById('maxPiecesInput');
366+
const defaultsButton = document.getElementById('defaultsButton'); // New defaults button
343367

344-
// Added more granular small sizes
345368
const PUZZLE_PIECE_SIZES = [1, 2, 3, 4, 5, 6, 7, 8, 16, 32, 64, 128, 256, 512];
346369

347370
let TARGET_MAX_PIECES = 100000;
@@ -351,14 +374,14 @@ <h2>Pixel Swirl</h2>
351374
const DEFAULT_GRAVITY_MIN = 0.01;
352375
const DEFAULT_GRAVITY_MAX = 0.5;
353376
const DEFAULT_SNAP_MAX = 16;
354-
const DEFAULT_REPEL_MAX = 1; // New default repel max
377+
const DEFAULT_REPEL_MAX = 1;
355378

356379
// Unlocked ranges for sliders
357380
const UNLOCKED_SPEED_MAX = 10;
358381
const UNLOCKED_GRAVITY_MIN = 0.001;
359382
const UNLOCKED_GRAVITY_MAX = 0.99;
360383
const UNLOCKED_SNAP_MAX = 256;
361-
const UNLOCKED_REPEL_MAX = 5; // New unlocked repel max
384+
const UNLOCKED_REPEL_MAX = 5;
362385

363386

364387
let gl = null;
@@ -373,8 +396,8 @@ <h2>Pixel Swirl</h2>
373396
let animationSpeed = 1;
374397
let gravityForce = 0.05;
375398
let snapDistance = 0;
376-
let repelForce = 0; // New: Repel force
377-
let repelFrequency = 0; // New: Repel frequency (0-10)
399+
let repelForce = 0;
400+
let repelFrequency = 0; // In seconds (0-10)
378401

379402
let puzzlePieces = [];
380403
let originalImageWidth = 0;
@@ -385,9 +408,11 @@ <h2>Pixel Swirl</h2>
385408
let allPositions = null;
386409
let allTexCoords = null;
387410

388-
// Stores the user's preferred pixel size index, to be restored on restart
389411
let lastSetPuzzlePieceSizeIndex = PUZZLE_PIECE_SIZES.indexOf(64);
390412

413+
// For frequency-based repel
414+
let lastRepelTime = 0; // Timestamp of the last repel impulse
415+
391416

392417
// --- Shaders ---
393418
const vsSource = `
@@ -505,7 +530,7 @@ <h2>Pixel Swirl</h2>
505530
this.swirlSpeed = Math.random() * 0.05 + 0.01;
506531
}
507532

508-
update() {
533+
update(deltaTime) { // Add deltaTime parameter for frame-independent updates
509534
if (this.settled) {
510535
return;
511536
}
@@ -540,14 +565,13 @@ <h2>Pixel Swirl</h2>
540565

541566
let effectiveForce = gravityForce * animationSpeed; // Default to attraction
542567

543-
// Repel logic: if repelForce is active and a random check passes
544-
if (repelForce > 0 && repelFrequency > 0) {
545-
if (Math.random() * 10 < repelFrequency) { // Probability check (e.g., 5/10 chance if frequency=5)
546-
effectiveForce = -repelForce; // Negative force means repulsion
547-
}
568+
// Repel logic: only apply if the global condition for repel is met this frame
569+
// (This piece does not do the frequency check itself, a global timer does)
570+
if (repelForce > 0 && repelFrequency > 0 && repelTriggeredThisFrame) {
571+
effectiveForce = -repelForce; // Negative force means repulsion
548572
}
549573

550-
this.vx += swirlDx * effectiveForce; // Apply the calculated effective force
574+
this.vx += swirlDx * effectiveForce;
551575
this.vy += swirlDy * effectiveForce;
552576

553577
this.vx *= this.damping;
@@ -625,12 +649,11 @@ <h2>Pixel Swirl</h2>
625649

626650
function updatePieceSizeSliderRange() {
627651
if (unlockPieceSizeCheckbox.checked) {
628-
pixelSizeSlider.min = 0; // Allow 1x1 pieces
652+
pixelSizeSlider.min = 0;
629653
} else {
630654
pixelSizeSlider.min = currentMinPieceSizeIndex;
631655
}
632656

633-
// Ensure slider value is not below the new minimum or above max
634657
let sliderVal = parseInt(pixelSizeSlider.value);
635658
const sliderMin = parseInt(pixelSizeSlider.min);
636659
const sliderMax = parseInt(pixelSizeSlider.max);
@@ -770,15 +793,38 @@ <h2>Pixel Swirl</h2>
770793
startAnimation();
771794
}
772795

773-
function drawScene() {
796+
let previousTimeStamp = 0;
797+
let repelTriggeredThisFrame = false; // Flag to indicate if repel is active for the current frame
798+
799+
function drawScene(currentTimeStamp) {
800+
if (!previousTimeStamp) previousTimeStamp = currentTimeStamp;
801+
const deltaTime = (currentTimeStamp - previousTimeStamp) / 1000; // Convert to seconds
802+
previousTimeStamp = currentTimeStamp;
803+
774804
gl.clear(gl.COLOR_BUFFER_BIT);
775805

776806
let currentPositionIndex = 0;
777807
let allSettled = true;
778808

809+
// Determine if a repel impulse should be triggered this frame
810+
repelTriggeredThisFrame = false;
811+
if (repelForce > 0 && repelFrequency > 0) {
812+
// Time since last repel in milliseconds
813+
const timeSinceLastRepel = currentTimeStamp - lastRepelTime;
814+
// Required interval in milliseconds
815+
const requiredInterval = repelFrequency * 1000;
816+
817+
if (timeSinceLastRepel >= requiredInterval) {
818+
repelTriggeredThisFrame = true;
819+
lastRepelTime = currentTimeStamp; // Update last repel time
820+
console.log(`Repel triggered at ${currentTimeStamp.toFixed(0)}ms (interval: ${requiredInterval}ms)`);
821+
}
822+
}
823+
824+
779825
puzzlePieces.forEach(piece => {
780826
if (!piece.settled) {
781-
piece.update();
827+
piece.update(deltaTime); // Pass deltaTime to update if piece logic needs it (not currently for this version, but good practice)
782828
allSettled = false;
783829
}
784830

@@ -838,6 +884,8 @@ <h2>Pixel Swirl</h2>
838884
p.vx = 0;
839885
p.vy = 0;
840886
});
887+
lastRepelTime = performance.now(); // Reset repel timer on animation start
888+
previousTimeStamp = 0; // Reset previous timestamp for accurate delta time
841889
drawScene();
842890
}
843891
}
@@ -854,14 +902,12 @@ <h2>Pixel Swirl</h2>
854902
originalImageObject = img;
855903
resizeCanvasToImage(img);
856904

857-
// Store the current pixel size before potentially adjusting for new image/max pieces
858905
lastSetPuzzlePieceSizeIndex = parseInt(pixelSizeSlider.value);
859906

860907
calculateMinPieceSizeForImage();
861908

862-
// Set slider to the greater of user's last setting or the new minimum
863909
pixelSizeSlider.value = Math.max(lastSetPuzzlePieceSizeIndex, currentMinPieceSizeIndex);
864-
pixelSizeSlider.dispatchEvent(new Event('input')); // This will call createPuzzlePiecesFromImage()
910+
pixelSizeSlider.dispatchEvent(new Event('input'));
865911
};
866912
img.src = e.target.result;
867913
};
@@ -882,9 +928,8 @@ <h2>Pixel Swirl</h2>
882928

883929
calculateMinPieceSizeForImage();
884930

885-
// Set slider to the greater of user's last setting or the new minimum
886931
pixelSizeSlider.value = Math.max(lastSetPuzzlePieceSizeIndex, currentMinPieceSizeIndex);
887-
pixelSizeSlider.dispatchEvent(new Event('input')); // This will trigger createPuzzlePiecesFromImage()
932+
pixelSizeSlider.dispatchEvent(new Event('input'));
888933
} else {
889934
alert("Please load an image first!");
890935
}
@@ -895,7 +940,6 @@ <h2>Pixel Swirl</h2>
895940
speedValueSpan.textContent = animationSpeed.toFixed(1);
896941
puzzlePieces.forEach(p => {
897942
p.maxSpeed = 10 * animationSpeed;
898-
// No need to update p.attractionForce here, it's calculated in update()
899943
});
900944
if (animationFrameId === null && originalImageObject) {
901945
startAnimation();
@@ -906,7 +950,7 @@ <h2>Pixel Swirl</h2>
906950
const sliderIndex = parseInt(event.target.value);
907951
currentPuzzlePieceSize = PUZZLE_PIECE_SIZES[sliderIndex];
908952
pixelSizeValueSpan.textContent = `${currentPuzzlePieceSize}x${currentPuzzlePieceSize}`;
909-
lastSetPuzzlePieceSizeIndex = sliderIndex; // Save the current slider index
953+
lastSetPuzzlePieceSizeIndex = sliderIndex;
910954
if (originalImageObject) {
911955
createPuzzlePiecesFromImage();
912956
}
@@ -934,7 +978,6 @@ <h2>Pixel Swirl</h2>
934978
gravitySlider.addEventListener('input', (event) => {
935979
gravityForce = parseFloat(event.target.value);
936980
gravityValueSpan.textContent = gravityForce.toFixed(gravityForce < 0.01 ? 3 : 2);
937-
// PuzzlePiece.update uses gravityForce directly, no need to loop here
938981
if (animationFrameId === null && originalImageObject) {
939982
startAnimation();
940983
}
@@ -947,15 +990,20 @@ <h2>Pixel Swirl</h2>
947990

948991
repelSlider.addEventListener('input', (event) => {
949992
repelForce = parseFloat(event.target.value);
950-
repelValueSpan.textContent = repelForce.toFixed(2); // Display 2 decimal places for repel
993+
repelValueSpan.textContent = repelForce.toFixed(2);
994+
// If repel is turned on from 0, or changed, and not animating, start it.
951995
if (animationFrameId === null && originalImageObject) {
952996
startAnimation();
953997
}
954998
});
955999

9561000
frequencySlider.addEventListener('input', (event) => {
9571001
repelFrequency = parseInt(event.target.value);
958-
frequencyValueSpan.textContent = repelFrequency.toString(); // Display as integer
1002+
frequencyValueSpan.textContent = repelFrequency.toString();
1003+
// Reset lastRepelTime when frequency changes to ensure immediate effect or proper new timing
1004+
if (repelFrequency > 0) {
1005+
lastRepelTime = performance.now();
1006+
}
9591007
if (animationFrameId === null && originalImageObject) {
9601008
startAnimation();
9611009
}
@@ -972,13 +1020,13 @@ <h2>Pixel Swirl</h2>
9721020
gravitySlider.min = UNLOCKED_GRAVITY_MIN;
9731021
gravitySlider.max = UNLOCKED_GRAVITY_MAX;
9741022
snapDistanceSlider.max = UNLOCKED_SNAP_MAX;
975-
repelSlider.max = UNLOCKED_REPEL_MAX; // Unlocked repel max
1023+
repelSlider.max = UNLOCKED_REPEL_MAX;
9761024
} else {
9771025
speedSlider.max = DEFAULT_SPEED_MAX;
9781026
gravitySlider.min = DEFAULT_GRAVITY_MIN;
9791027
gravitySlider.max = DEFAULT_GRAVITY_MAX;
9801028
snapDistanceSlider.max = DEFAULT_SNAP_MAX;
981-
repelSlider.max = DEFAULT_REPEL_MAX; // Default repel max
1029+
repelSlider.max = DEFAULT_REPEL_MAX;
9821030
}
9831031
// Ensure values are within new bounds and update display
9841032
speedSlider.value = Math.min(parseFloat(speedSlider.value), parseFloat(speedSlider.max));
@@ -1009,9 +1057,37 @@ <h2>Pixel Swirl</h2>
10091057
console.log("Max # of Pieces changed to:", maxPiecesInput.value, "Will apply on Restart.");
10101058
});
10111059

1060+
defaultsButton.addEventListener('click', () => {
1061+
// Reset all sliders to their default initial values
1062+
speedSlider.value = 1;
1063+
gravitySlider.value = 0.05;
1064+
snapDistanceSlider.value = 0;
1065+
repelSlider.value = 0;
1066+
frequencySlider.value = 0;
1067+
maxPiecesInput.value = 100000;
1068+
pixelSizeSlider.value = PUZZLE_PIECE_SIZES.indexOf(64); // Reset to 64x64
1069+
lastSetPuzzlePieceSizeIndex = PUZZLE_PIECE_SIZES.indexOf(64);
1070+
1071+
// Reset checkboxes
1072+
unlockFreedomCheckbox.checked = false;
1073+
unlockPieceSizeCheckbox.checked = false;
1074+
1075+
// Trigger input events to update UI and apply values
1076+
speedSlider.dispatchEvent(new Event('input'));
1077+
gravitySlider.dispatchEvent(new Event('input'));
1078+
snapDistanceSlider.dispatchEvent(new Event('input'));
1079+
repelSlider.dispatchEvent(new Event('input'));
1080+
frequencySlider.dispatchEvent(new Event('input'));
1081+
maxPiecesInput.dispatchEvent(new Event('change')); // Use 'change' for number inputs
1082+
pixelSizeSlider.dispatchEvent(new Event('input')); // This also handles createPuzzlePiecesFromImage
1083+
unlockFreedomCheckbox.dispatchEvent(new Event('change')); // This re-sets slider ranges
1084+
unlockPieceSizeCheckbox.dispatchEvent(new Event('change'));
1085+
1086+
console.log("All settings reset to defaults.");
1087+
});
10121088

10131089
// App Versioning
1014-
const APP_VERSION = 1.006;
1090+
const APP_VERSION = 1.007;
10151091

10161092
// Initialize on load
10171093
window.onload = () => {
@@ -1023,7 +1099,7 @@ <h2>Pixel Swirl</h2>
10231099
pixelSizeSlider.value = 0;
10241100
currentPuzzlePieceSize = PUZZLE_PIECE_SIZES[0];
10251101
}
1026-
lastSetPuzzlePieceSizeIndex = parseInt(pixelSizeSlider.value); // Store initial value
1102+
lastSetPuzzlePieceSizeIndex = parseInt(pixelSizeSlider.value);
10271103

10281104
pixelSizeValueSpan.textContent = `${currentPuzzlePieceSize}x${currentPuzzlePieceSize}`;
10291105

@@ -1032,8 +1108,8 @@ <h2>Pixel Swirl</h2>
10321108
gravitySlider.min = DEFAULT_GRAVITY_MIN;
10331109
gravitySlider.max = DEFAULT_GRAVITY_MAX;
10341110
snapDistanceSlider.max = DEFAULT_SNAP_MAX;
1035-
repelSlider.max = DEFAULT_REPEL_MAX; // Set initial repel max
1036-
frequencySlider.max = 10; // Frequency max is constant
1111+
repelSlider.max = DEFAULT_REPEL_MAX;
1112+
frequencySlider.max = 10;
10371113

10381114
speedSlider.value = animationSpeed;
10391115
speedValueSpan.textContent = animationSpeed.toFixed(1);
@@ -1057,6 +1133,9 @@ <h2>Pixel Swirl</h2>
10571133

10581134
versionNumberSpan.textContent = `Version ${APP_VERSION.toFixed(3)}`;
10591135
document.title = `Pixel Swirl Version ${APP_VERSION.toFixed(3)}`;
1136+
1137+
// Initial setup for repel timing
1138+
lastRepelTime = performance.now();
10601139
}
10611140
};
10621141

0 commit comments

Comments
 (0)