commit e414c45c27b851238d64f5298594c0361a499664
Author: root <root@hub.scroll.pub> Date: 2024-12-29 00:18:25 +0000 Subject: Initial commit diff --git a/body.html b/body.html new file mode 100644 index 0000000..6f2e7b7 --- /dev/null +++ b/body.html @@ -0,0 +1,15 @@ +<main> + <div class="football-container"> + <div class="football"> + <div class="seam"></div> + <div class="seam rotate45"></div> + </div> + </div> + <div class="instructions"> + <p>Click and drag the football, then release to bounce!</p> + </div> + <div class="ground"></div> +</main> +<footer> + <p>Made with passion for football fans</p> +</footer> diff --git a/index.scroll b/index.scroll new file mode 100644 index 0000000..c04891c --- /dev/null +++ b/index.scroll @@ -0,0 +1,11 @@ +buildHtml +baseUrl https://bouncyball.scroll.pub +metaTags + title Interactive Bouncing Football + description Experience a realistic physics-based football simulation where you can grab and bounce a football using your mouse or touch + keywords football, physics, animation, interactive, game +editButton /edit.html +title Interactive Bouncing Football +style.css +body.html +script.js diff --git a/prompt.json b/prompt.json new file mode 100644 index 0000000..e597407 --- /dev/null +++ b/prompt.json @@ -0,0 +1,20 @@ +{ + "id": "msg_016G1qnokdNZ2kpifW4Kcucn", + "type": "message", + "role": "assistant", + "model": "claude-3-5-sonnet-20241022", + "content": [ + { + "type": "text", + "text": "Here's a fun, interactive football bouncing website:\n\n---domain---\nbouncyball.scroll.pub\n\n---index.scroll---\nbuildHtml\nbaseUrl https://bouncyball.scroll.pub\nmetaTags\n title Interactive Bouncing Football\n description Experience a realistic physics-based football simulation where you can grab and bounce a football using your mouse or touch\n keywords football, physics, animation, interactive, game\neditButton /edit.html\ntitle Interactive Bouncing Football\nstyle.css\nbody.html\nscript.js\n\n---body.html---\n<main>\n <div class=\"football-container\">\n <div class=\"football\">\n <div class=\"seam\"></div>\n <div class=\"seam rotate45\"></div>\n </div>\n </div>\n <div class=\"instructions\">\n <p>Click and drag the football, then release to bounce!</p>\n </div>\n <div class=\"ground\"></div>\n</main>\n<footer>\n <p>Made with passion for football fans</p>\n</footer>\n\n---style.css---\n:root {\n --ball-brown: #8B4513;\n --seam-color: #F5F5F5;\n --ground-color: #2E7D32;\n}\n\n* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n min-height: 100vh;\n background: linear-gradient(180deg, #87CEEB, #E0F7FA);\n overflow: hidden;\n font-family: system-ui, sans-serif;\n}\n\nmain {\n height: 100vh;\n display: flex;\n flex-direction: column;\n align-items: center;\n position: relative;\n}\n\n.football-container {\n flex: 1;\n width: 100%;\n position: relative;\n}\n\n.football {\n width: 100px;\n height: 60px;\n background: var(--ball-brown);\n border-radius: 50%;\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n cursor: grab;\n box-shadow: inset -10px -10px 15px rgba(0,0,0,0.3);\n transition: transform 0.2s;\n}\n\n.football:active {\n cursor: grabbing;\n}\n\n.seam {\n position: absolute;\n width: 100%;\n height: 4px;\n background: var(--seam-color);\n top: 50%;\n transform: translateY(-50%);\n}\n\n.rotate45 {\n transform: rotate(45deg);\n}\n\n.instructions {\n text-align: center;\n padding: 1rem;\n background: rgba(255,255,255,0.8);\n border-radius: 10px;\n margin: 1rem;\n z-index: 10;\n}\n\n.ground {\n width: 100%;\n height: 100px;\n background: var(--ground-color);\n position: absolute;\n bottom: 0;\n}\n\nfooter {\n position: absolute;\n bottom: 0;\n width: 100%;\n text-align: center;\n padding: 1rem;\n color: white;\n background: rgba(0,0,0,0.5);\n}\n\n@media (max-width: 768px) {\n .football {\n width: 80px;\n height: 48px;\n }\n \n .instructions {\n font-size: 0.9rem;\n }\n}\n\n---script.js---\ndocument.addEventListener('DOMContentLoaded', () => {\n const football = document.querySelector('.football');\n let isDragging = false;\n let currentX, currentY, initialX, initialY;\n let xOffset = 0;\n let yOffset = 0;\n let velocity = { x: 0, y: 0 };\n let lastPos = { x: 0, y: 0 };\n let animationId;\n\n const gravity = 0.5;\n const bounce = 0.7;\n const friction = 0.99;\n\n function dragStart(e) {\n if (e.type === \"touchstart\") {\n initialX = e.touches[0].clientX - xOffset;\n initialY = e.touches[0].clientY - yOffset;\n } else {\n initialX = e.clientX - xOffset;\n initialY = e.clientY - yOffset;\n }\n \n if (e.target === football) {\n isDragging = true;\n cancelAnimationFrame(animationId);\n }\n }\n\n function drag(e) {\n if (isDragging) {\n e.preventDefault();\n\n if (e.type === \"touchmove\") {\n currentX = e.touches[0].clientX - initialX;\n currentY = e.touches[0].clientY - initialY;\n } else {\n currentX = e.clientX - initialX;\n currentY = e.clientY - initialY;\n }\n\n xOffset = currentX;\n yOffset = currentY;\n\n velocity.x = currentX - lastPos.x;\n velocity.y = currentY - lastPos.y;\n \n lastPos.x = currentX;\n lastPos.y = currentY;\n\n setTranslate(currentX, currentY, football);\n }\n }\n\n function setTranslate(xPos, yPos, el) {\n el.style.transform = `translate(${xPos}px, ${yPos}px) rotate(${xPos * 0.2}deg)`;\n }\n\n function dragEnd() {\n if (isDragging) {\n isDragging = false;\n animate();\n }\n }\n\n function animate() {\n if (!isDragging) {\n velocity.y += gravity;\n velocity.x *= friction;\n \n xOffset += velocity.x;\n yOffset += velocity.y;\n\n const ground = window.innerHeight - 160;\n \n if (yOffset > ground) {\n yOffset = ground;\n velocity.y *= -bounce;\n }\n\n if (Math.abs(xOffset) > window.innerWidth/2) {\n velocity.x *= -1;\n xOffset = Math.sign(xOffset) * window.innerWidth/2;\n }\n\n setTranslate(xOffset, yOffset, football);\n \n if (Math.abs(velocity.y) > 0.1 || Math.abs(velocity.x) > 0.1) {\n animationId = requestAnimationFrame(animate);\n }\n }\n }\n\n football.addEventListener('mousedown', dragStart);\n football.addEventListener('touchstart', dragStart, { passive: false });\n document.addEventListener('mousemove', drag);\n document.addEventListener('touchmove', drag, { passive: false });\n document.addEventListener('mouseup', dragEnd);\n document.addEventListener('touchend', dragEnd);\n});\n\n---end---\n\nThis creates a fun interactive website where users can grab and bounce a realistic-looking football. The ball responds to physics with gravity, bounce, and friction effects. Key features:\n\n1. Realistic football design with seams and shading\n2. Physics-based bouncing animation\n3. Smooth drag and release mechanics\n4. Responsive design that works on both desktop and mobile\n5. Beautiful gradient sky background\n6. Grass ground effect\n7. Clear user instructions\n8. Smooth rotational effects while the ball moves\n9. Touch support for mobile devices\n10. Boundary detection to keep the ball on screen\n\nThe code uses requestAnimationFrame for smooth animations and includes touch event handling for mobile devices. The CSS creates a realistic football appearance with shadows and seams, while the JavaScript handles the physics simulation and user interactions." + } + ], + "stop_reason": "end_turn", + "stop_sequence": null, + "usage": { + "input_tokens": 292, + "cache_creation_input_tokens": 0, + "cache_read_input_tokens": 0, + "output_tokens": 1948 + } +} \ No newline at end of file diff --git a/readme.scroll b/readme.scroll new file mode 100644 index 0000000..0d8ec88 --- /dev/null +++ b/readme.scroll @@ -0,0 +1,2 @@ +# bouncyball.scroll.pub +Website generated by Claude from prompt: create a site that have a realistic football ball that can be hold with the mouse and when released it bounces \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 0000000..b042f28 --- /dev/null +++ b/script.js @@ -0,0 +1,100 @@ +document.addEventListener('DOMContentLoaded', () => { + const football = document.querySelector('.football'); + let isDragging = false; + let currentX, currentY, initialX, initialY; + let xOffset = 0; + let yOffset = 0; + let velocity = { x: 0, y: 0 }; + let lastPos = { x: 0, y: 0 }; + let animationId; + + const gravity = 0.5; + const bounce = 0.7; + const friction = 0.99; + + function dragStart(e) { + if (e.type === "touchstart") { + initialX = e.touches[0].clientX - xOffset; + initialY = e.touches[0].clientY - yOffset; + } else { + initialX = e.clientX - xOffset; + initialY = e.clientY - yOffset; + } + + if (e.target === football) { + isDragging = true; + cancelAnimationFrame(animationId); + } + } + + function drag(e) { + if (isDragging) { + e.preventDefault(); + + if (e.type === "touchmove") { + currentX = e.touches[0].clientX - initialX; + currentY = e.touches[0].clientY - initialY; + } else { + currentX = e.clientX - initialX; + currentY = e.clientY - initialY; + } + + xOffset = currentX; + yOffset = currentY; + + velocity.x = currentX - lastPos.x; + velocity.y = currentY - lastPos.y; + + lastPos.x = currentX; + lastPos.y = currentY; + + setTranslate(currentX, currentY, football); + } + } + + function setTranslate(xPos, yPos, el) { + el.style.transform = `translate(${xPos}px, ${yPos}px) rotate(${xPos * 0.2}deg)`; + } + + function dragEnd() { + if (isDragging) { + isDragging = false; + animate(); + } + } + + function animate() { + if (!isDragging) { + velocity.y += gravity; + velocity.x *= friction; + + xOffset += velocity.x; + yOffset += velocity.y; + + const ground = window.innerHeight - 160; + + if (yOffset > ground) { + yOffset = ground; + velocity.y *= -bounce; + } + + if (Math.abs(xOffset) > window.innerWidth/2) { + velocity.x *= -1; + xOffset = Math.sign(xOffset) * window.innerWidth/2; + } + + setTranslate(xOffset, yOffset, football); + + if (Math.abs(velocity.y) > 0.1 || Math.abs(velocity.x) > 0.1) { + animationId = requestAnimationFrame(animate); + } + } + } + + football.addEventListener('mousedown', dragStart); + football.addEventListener('touchstart', dragStart, { passive: false }); + document.addEventListener('mousemove', drag); + document.addEventListener('touchmove', drag, { passive: false }); + document.addEventListener('mouseup', dragEnd); + document.addEventListener('touchend', dragEnd); +}); diff --git a/style.css b/style.css new file mode 100644 index 0000000..d3f5906 --- /dev/null +++ b/style.css @@ -0,0 +1,101 @@ +:root { + --ball-brown: #8B4513; + --seam-color: #F5F5F5; + --ground-color: #2E7D32; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + min-height: 100vh; + background: linear-gradient(180deg, #87CEEB, #E0F7FA); + overflow: hidden; + font-family: system-ui, sans-serif; +} + +main { + height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + position: relative; +} + +.football-container { + flex: 1; + width: 100%; + position: relative; +} + +.football { + width: 100px; + height: 60px; + background: var(--ball-brown); + border-radius: 50%; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + cursor: grab; + box-shadow: inset -10px -10px 15px rgba(0,0,0,0.3); + transition: transform 0.2s; +} + +.football:active { + cursor: grabbing; +} + +.seam { + position: absolute; + width: 100%; + height: 4px; + background: var(--seam-color); + top: 50%; + transform: translateY(-50%); +} + +.rotate45 { + transform: rotate(45deg); +} + +.instructions { + text-align: center; + padding: 1rem; + background: rgba(255,255,255,0.8); + border-radius: 10px; + margin: 1rem; + z-index: 10; +} + +.ground { + width: 100%; + height: 100px; + background: var(--ground-color); + position: absolute; + bottom: 0; +} + +footer { + position: absolute; + bottom: 0; + width: 100%; + text-align: center; + padding: 1rem; + color: white; + background: rgba(0,0,0,0.5); +} + +@media (max-width: 768px) { + .football { + width: 80px; + height: 48px; + } + + .instructions { + font-size: 0.9rem; + } +}