dupliter balloon accelerator ver 3
by dupliter
HTML
<div id="dupliter-container">
<h1>Dupliter Temporal Balloon</h1>
<p>Visualize past, present, and future states of an object with Dupliter. Adjust the sliders to explore temporal displacement and echo opacity.</p>
<svg id="balloonCanvas" width="600" height="400"></svg>
<div class="sliders">
<label>Temporal Displacement:
<input type="range" id="displacementSlider" min="0" max="150" value="0">
</label>
<label>Echo Opacity:
<input type="range" id="opacitySlider" min="0.1" max="1" value="0.4" step="0.05">
</label>
</div>
<h2>Dupliter Temporal Pulse Example</h2>
<svg width="200" height="200" id="pulseCanvas"></svg>
</div>
CSS
body {
font-family: "Segoe UI", sans-serif;
text-align: center;
background-color: #f9f9f9;
padding: 20px;
}
#dupliter-container {
display: inline-block;
}
#balloonCanvas, #pulseCanvas {
border: 1px solid black;
background: white;
display: block;
margin: 20px auto;
}
.sliders {
display: flex;
justify-content: center;
gap: 20px;
flex-wrap: wrap;
}
input[type=range] {
width: 180px;
margin: 10px;
}
JavaScript
// --- Dupliter Balloon ---
const svg = document.getElementById("balloonCanvas");
const displacementSlider = document.getElementById("displacementSlider");
const opacitySlider = document.getElementById("opacitySlider");
// SVG blur filter for echoes
const defs = document.createElementNS("http://www.w3.org/2000/svg", "defs");
const filter = document.createElementNS("http://www.w3.org/2000/svg", "filter");
filter.setAttribute("id", "blur1");
const feGaussianBlur = document.createElementNS("http://www.w3.org/2000/svg", "feGaussianBlur");
feGaussianBlur.setAttribute("stdDeviation", "6");
filter.appendChild(feGaussianBlur);
defs.appendChild(filter);
svg.appendChild(defs);
function createCircle(cx, cy, r, fill, blur=0) {
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
circle.setAttribute("cx", cx);
circle.setAttribute("cy", cy);
circle.setAttribute("r", r);
circle.setAttribute("fill", fill);
if (blur) circle.setAttribute("filter", `url(#blur1)`);
return circle;
}
function createLabel(cx, cy, text) {
const label = document.createElementNS("http://www.w3.org/2000/svg", "text");
label.setAttribute("x", cx);
label.setAttribute("y", cy + 5); // center vertically
label.setAttribute("text-anchor", "middle");
label.setAttribute("fill", "white");
label.setAttribute("font-size", "14");
label.textContent = text;
return label;
}
function drawBalloon(displacement, opacity) {
svg.querySelectorAll("circle, text").forEach(el => el.remove());
// Past echo
svg.appendChild(createCircle(300 - displacement, 200, 60, `rgba(255,0,0,${opacity})`, 1));
svg.appendChild(createLabel(300 - displacement, 200, "Past"));
// Present
svg.appendChild(createCircle(300, 200, 60, "red"));
svg.appendChild(createLabel(300, 200, "Present"));
// Future echo
svg.appendChild(createCircle(300 + displacement, 200, 60, `rgba(255,0,0,${opacity})`, 1));
...