commit 00ed3ec6601bcfc8a9842fdf21060be53bb333be
Author: root <root@hub.scroll.pub>
Date: 2024-12-30 03:15:09 +0000
Subject: Initial commit
diff --git a/body.html b/body.html
new file mode 100644
index 0000000..6ce722d
--- /dev/null
+++ b/body.html
@@ -0,0 +1,21 @@
+<header>
+ <h1>Bouncing Balls</h1>
+ <p>An interactive physics simulation</p>
+</header>
+
+<main>
+ <div class="controls">
+ <button id="addBall" aria-label="Add new ball">Add Ball</button>
+ <button id="reset" aria-label="Reset simulation">Reset</button>
+ <label for="gravity">Gravity:</label>
+ <input type="range" id="gravity" min="0.1" max="2" step="0.1" value="0.8">
+ </div>
+
+ <canvas id="ballCanvas" aria-label="Bouncing balls animation canvas">
+ Your browser does not support the canvas element.
+ </canvas>
+</main>
+
+<footer>
+ <p>Created with love for physics and animation</p>
+</footer>
diff --git a/index.scroll b/index.scroll
new file mode 100644
index 0000000..1c5d47d
--- /dev/null
+++ b/index.scroll
@@ -0,0 +1,8 @@
+buildHtml
+baseUrl https://bouncebox.scroll.pub
+metaTags
+editButton /edit.html
+title Bouncing Balls Physics Demo
+style.css
+body.html
+script.js
diff --git a/prompt.json b/prompt.json
new file mode 100644
index 0000000..eb7632a
--- /dev/null
+++ b/prompt.json
@@ -0,0 +1,20 @@
+{
+ "id": "msg_01MZYJygyrvoiRpAqR3gt1xR",
+ "type": "message",
+ "role": "assistant",
+ "model": "claude-3-5-sonnet-20241022",
+ "content": [
+ {
+ "type": "text",
+ "text": "I'll create a fun and interactive bouncing balls demo website.\n\n---domain---\nbouncebox.scroll.pub\n\n---index.scroll---\nbuildHtml\nbaseUrl https://bouncebox.scroll.pub\nmetaTags\neditButton /edit.html\ntitle Bouncing Balls Physics Demo\nstyle.css\nbody.html\nscript.js\n\n---body.html---\n<header>\n <h1>Bouncing Balls</h1>\n <p>An interactive physics simulation</p>\n</header>\n\n<main>\n <div class=\"controls\">\n <button id=\"addBall\" aria-label=\"Add new ball\">Add Ball</button>\n <button id=\"reset\" aria-label=\"Reset simulation\">Reset</button>\n <label for=\"gravity\">Gravity:</label>\n <input type=\"range\" id=\"gravity\" min=\"0.1\" max=\"2\" step=\"0.1\" value=\"0.8\">\n </div>\n \n <canvas id=\"ballCanvas\" aria-label=\"Bouncing balls animation canvas\">\n Your browser does not support the canvas element.\n </canvas>\n</main>\n\n<footer>\n <p>Created with love for physics and animation</p>\n</footer>\n\n---style.css---\n:root {\n --primary-color: #2a2b2e;\n --accent-color: #4a90e2;\n --text-color: #ffffff;\n --shadow-color: rgba(0, 0, 0, 0.2);\n}\n\n* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n font-family: 'Segoe UI', system-ui, sans-serif;\n background: linear-gradient(135deg, #1a1b1f 0%, #2a2b2e 100%);\n color: var(--text-color);\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\nheader {\n text-align: center;\n padding: 2rem;\n background: rgba(255, 255, 255, 0.05);\n backdrop-filter: blur(10px);\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n\nh1 {\n font-size: 2.5rem;\n margin-bottom: 0.5rem;\n background: linear-gradient(45deg, var(--accent-color), #6ab0ff);\n -webkit-background-clip: text;\n background-clip: text;\n color: transparent;\n text-shadow: 2px 2px 4px var(--shadow-color);\n}\n\n.controls {\n position: fixed;\n top: 1rem;\n right: 1rem;\n display: flex;\n gap: 1rem;\n padding: 1rem;\n background: rgba(255, 255, 255, 0.1);\n backdrop-filter: blur(5px);\n border-radius: 12px;\n z-index: 100;\n}\n\nbutton {\n padding: 0.5rem 1rem;\n border: none;\n border-radius: 6px;\n background: var(--accent-color);\n color: var(--text-color);\n cursor: pointer;\n transition: transform 0.2s, background 0.2s;\n}\n\nbutton:hover {\n transform: translateY(-2px);\n background: #5fa0f2;\n}\n\ninput[type=\"range\"] {\n width: 100px;\n accent-color: var(--accent-color);\n}\n\ncanvas {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 1;\n}\n\nfooter {\n position: fixed;\n bottom: 0;\n width: 100%;\n padding: 1rem;\n text-align: center;\n background: rgba(255, 255, 255, 0.05);\n backdrop-filter: blur(10px);\n z-index: 100;\n}\n\n@media (max-width: 768px) {\n .controls {\n flex-direction: column;\n right: 0.5rem;\n top: 0.5rem;\n }\n \n h1 {\n font-size: 2rem;\n }\n}\n\n---script.js---\nclass Ball {\n constructor(x, y) {\n this.x = x;\n this.y = y;\n this.vx = (Math.random() - 0.5) * 10;\n this.vy = (Math.random() - 0.5) * 10;\n this.radius = Math.random() * 20 + 10;\n this.color = `hsl(${Math.random() * 360}, 70%, 50%)`;\n }\n}\n\nclass BallSimulation {\n constructor() {\n this.canvas = document.getElementById('ballCanvas');\n this.ctx = this.canvas.getContext('2d');\n this.balls = [];\n this.gravity = 0.8;\n this.friction = 0.99;\n this.bounce = 0.8;\n \n this.resize();\n this.setupEventListeners();\n this.animate();\n }\n\n resize() {\n this.canvas.width = window.innerWidth;\n this.canvas.height = window.innerHeight;\n }\n\n setupEventListeners() {\n window.addEventListener('resize', () => this.resize());\n \n document.getElementById('addBall').addEventListener('click', () => {\n this.addBall(this.canvas.width / 2, this.canvas.height / 3);\n });\n \n document.getElementById('reset').addEventListener('click', () => {\n this.balls = [];\n });\n \n document.getElementById('gravity').addEventListener('input', (e) => {\n this.gravity = parseFloat(e.target.value);\n });\n \n this.canvas.addEventListener('click', (e) => {\n const rect = this.canvas.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n this.addBall(x, y);\n });\n }\n\n addBall(x, y) {\n this.balls.push(new Ball(x, y));\n }\n\n update() {\n this.balls.forEach(ball => {\n ball.vy += this.gravity;\n ball.x += ball.vx;\n ball.y += ball.vy;\n \n ball.vx *= this.friction;\n ball.vy *= this.friction;\n \n if (ball.x + ball.radius > this.canvas.width) {\n ball.x = this.canvas.width - ball.radius;\n ball.vx *= -this.bounce;\n }\n if (ball.x - ball.radius < 0) {\n ball.x = ball.radius;\n ball.vx *= -this.bounce;\n }\n if (ball.y + ball.radius > this.canvas.height) {\n ball.y = this.canvas.height - ball.radius;\n ball.vy *= -this.bounce;\n }\n if (ball.y - ball.radius < 0) {\n ball.y = ball.radius;\n ball.vy *= -this.bounce;\n }\n });\n }\n\n draw() {\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n \n this.balls.forEach(ball => {\n this.ctx.beginPath();\n this.ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);\n this.ctx.fillStyle = ball.color;\n this.ctx.fill();\n this.ctx.closePath();\n \n // Add shadow\n this.ctx.shadowColor = 'rgba(0, 0, 0, 0.3)';\n this.ctx.shadowBlur = 10;\n this.ctx.shadowOffsetX = 5;\n this.ctx.shadowOffsetY = 5;\n });\n }\n\n animate() {\n this.update();\n this.draw();\n requestAnimationFrame(() => this.animate());\n }\n}\n\ndocument.addEventListener('DOMContentLoaded', () => {\n new BallSimulation();\n});\n\n---end---\n\nThis creates a beautiful, interactive bouncing balls physics simulation with the following features:\n\n1. Click anywhere on the canvas to add balls\n2. Use the \"Add Ball\" button to add balls at the center\n3. Adjust gravity with the slider\n4. Reset button to clear all balls\n5. Smooth animations with requestAnimationFrame\n6. Beautiful gradient background and glassmorphism UI\n7. Responsive design that works on all devices\n8. Accessible controls with ARIA labels\n9. Realistic physics with gravity, friction, and bounce effects\n10. Colorful balls with shadows and random properties\n\nThe website uses modern CSS features like CSS variables, backdrop-filter for glassmorphism effects, and smooth animations. The JavaScript is organized using classes for better code structure and maintainability."
+ }
+ ],
+ "stop_reason": "end_turn",
+ "stop_sequence": null,
+ "usage": {
+ "input_tokens": 278,
+ "cache_creation_input_tokens": 0,
+ "cache_read_input_tokens": 0,
+ "output_tokens": 2312
+ }
+}
\ No newline at end of file
diff --git a/readme.scroll b/readme.scroll
new file mode 100644
index 0000000..a464b45
--- /dev/null
+++ b/readme.scroll
@@ -0,0 +1,2 @@
+# bouncebox.scroll.pub
+Website generated by Claude from prompt: A website to demo the bouncing balls.
\ No newline at end of file
diff --git a/script.js b/script.js
new file mode 100644
index 0000000..1565cb6
--- /dev/null
+++ b/script.js
@@ -0,0 +1,113 @@
+class Ball {
+ constructor(x, y) {
+ this.x = x;
+ this.y = y;
+ this.vx = (Math.random() - 0.5) * 10;
+ this.vy = (Math.random() - 0.5) * 10;
+ this.radius = Math.random() * 20 + 10;
+ this.color = `hsl(${Math.random() * 360}, 70%, 50%)`;
+ }
+}
+
+class BallSimulation {
+ constructor() {
+ this.canvas = document.getElementById('ballCanvas');
+ this.ctx = this.canvas.getContext('2d');
+ this.balls = [];
+ this.gravity = 0.8;
+ this.friction = 0.99;
+ this.bounce = 0.8;
+
+ this.resize();
+ this.setupEventListeners();
+ this.animate();
+ }
+
+ resize() {
+ this.canvas.width = window.innerWidth;
+ this.canvas.height = window.innerHeight;
+ }
+
+ setupEventListeners() {
+ window.addEventListener('resize', () => this.resize());
+
+ document.getElementById('addBall').addEventListener('click', () => {
+ this.addBall(this.canvas.width / 2, this.canvas.height / 3);
+ });
+
+ document.getElementById('reset').addEventListener('click', () => {
+ this.balls = [];
+ });
+
+ document.getElementById('gravity').addEventListener('input', (e) => {
+ this.gravity = parseFloat(e.target.value);
+ });
+
+ this.canvas.addEventListener('click', (e) => {
+ const rect = this.canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+ this.addBall(x, y);
+ });
+ }
+
+ addBall(x, y) {
+ this.balls.push(new Ball(x, y));
+ }
+
+ update() {
+ this.balls.forEach(ball => {
+ ball.vy += this.gravity;
+ ball.x += ball.vx;
+ ball.y += ball.vy;
+
+ ball.vx *= this.friction;
+ ball.vy *= this.friction;
+
+ if (ball.x + ball.radius > this.canvas.width) {
+ ball.x = this.canvas.width - ball.radius;
+ ball.vx *= -this.bounce;
+ }
+ if (ball.x - ball.radius < 0) {
+ ball.x = ball.radius;
+ ball.vx *= -this.bounce;
+ }
+ if (ball.y + ball.radius > this.canvas.height) {
+ ball.y = this.canvas.height - ball.radius;
+ ball.vy *= -this.bounce;
+ }
+ if (ball.y - ball.radius < 0) {
+ ball.y = ball.radius;
+ ball.vy *= -this.bounce;
+ }
+ });
+ }
+
+ draw() {
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
+
+ this.balls.forEach(ball => {
+ this.ctx.beginPath();
+ this.ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
+ this.ctx.fillStyle = ball.color;
+ this.ctx.fill();
+ this.ctx.closePath();
+
+ // Add shadow
+ this.ctx.shadowColor = 'rgba(0, 0, 0, 0.3)';
+ this.ctx.shadowBlur = 10;
+ this.ctx.shadowOffsetX = 5;
+ this.ctx.shadowOffsetY = 5;
+ });
+ }
+
+ animate() {
+ this.update();
+ this.draw();
+ requestAnimationFrame(() => this.animate());
+ }
+}
+
+document.addEventListener('DOMContentLoaded', () => {
+ new BallSimulation();
+});
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..b2f1f18
--- /dev/null
+++ b/style.css
@@ -0,0 +1,105 @@
+:root {
+ --primary-color: #2a2b2e;
+ --accent-color: #4a90e2;
+ --text-color: #ffffff;
+ --shadow-color: rgba(0, 0, 0, 0.2);
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: 'Segoe UI', system-ui, sans-serif;
+ background: linear-gradient(135deg, #1a1b1f 0%, #2a2b2e 100%);
+ color: var(--text-color);
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+}
+
+header {
+ text-align: center;
+ padding: 2rem;
+ background: rgba(255, 255, 255, 0.05);
+ backdrop-filter: blur(10px);
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
+}
+
+h1 {
+ font-size: 2.5rem;
+ margin-bottom: 0.5rem;
+ background: linear-gradient(45deg, var(--accent-color), #6ab0ff);
+ -webkit-background-clip: text;
+ background-clip: text;
+ color: transparent;
+ text-shadow: 2px 2px 4px var(--shadow-color);
+}
+
+.controls {
+ position: fixed;
+ top: 1rem;
+ right: 1rem;
+ display: flex;
+ gap: 1rem;
+ padding: 1rem;
+ background: rgba(255, 255, 255, 0.1);
+ backdrop-filter: blur(5px);
+ border-radius: 12px;
+ z-index: 100;
+}
+
+button {
+ padding: 0.5rem 1rem;
+ border: none;
+ border-radius: 6px;
+ background: var(--accent-color);
+ color: var(--text-color);
+ cursor: pointer;
+ transition: transform 0.2s, background 0.2s;
+}
+
+button:hover {
+ transform: translateY(-2px);
+ background: #5fa0f2;
+}
+
+input[type="range"] {
+ width: 100px;
+ accent-color: var(--accent-color);
+}
+
+canvas {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 1;
+}
+
+footer {
+ position: fixed;
+ bottom: 0;
+ width: 100%;
+ padding: 1rem;
+ text-align: center;
+ background: rgba(255, 255, 255, 0.05);
+ backdrop-filter: blur(10px);
+ z-index: 100;
+}
+
+@media (max-width: 768px) {
+ .controls {
+ flex-direction: column;
+ right: 0.5rem;
+ top: 0.5rem;
+ }
+
+ h1 {
+ font-size: 2rem;
+ }
+}