commit 2e456819174bade95c14a64377b7ee3581f66e7f
Author: root <root@hub.scroll.pub>
Date: 2024-12-27 23:55:41 +0000
Subject: Initial commit
diff --git a/body.html b/body.html
new file mode 100644
index 0000000..deccf57
--- /dev/null
+++ b/body.html
@@ -0,0 +1,37 @@
+<main class="container">
+ <header>
+ <h1>Canvas Play</h1>
+ <p>Create and manipulate 2D objects</p>
+ </header>
+
+ <section class="controls">
+ <div class="shape-controls">
+ <button id="addRectangle" aria-label="Add Rectangle">Rectangle</button>
+ <button id="addCircle" aria-label="Add Circle">Circle</button>
+ <button id="addTriangle" aria-label="Add Triangle">Triangle</button>
+ </div>
+
+ <div class="color-controls">
+ <input type="color" id="colorPicker" value="#ff4444" aria-label="Color picker">
+ <input type="range" id="sizeSlider" min="20" max="200" value="50" aria-label="Size slider">
+ </div>
+ </section>
+
+ <canvas id="canvas" aria-label="Drawing canvas">
+ Your browser does not support the canvas element.
+ </canvas>
+
+ <section class="instructions">
+ <h2>Instructions</h2>
+ <ul>
+ <li>Click buttons to add shapes</li>
+ <li>Use arrow keys to move selected shape</li>
+ <li>Click a shape to select it</li>
+ <li>Press Delete to remove selected shape</li>
+ </ul>
+ </section>
+</main>
+
+<footer>
+ <p>Created with love by Canvas Play</p>
+</footer>
diff --git a/index.scroll b/index.scroll
new file mode 100644
index 0000000..7a6a602
--- /dev/null
+++ b/index.scroll
@@ -0,0 +1,8 @@
+buildHtml
+baseUrl https://canvasplay.scroll.pub
+metaTags
+editButton /edit.html
+title Canvas Play - Interactive 2D Object Manipulator
+style.css
+body.html
+script.js
diff --git a/prompt.json b/prompt.json
new file mode 100644
index 0000000..359e3a6
--- /dev/null
+++ b/prompt.json
@@ -0,0 +1,20 @@
+{
+ "id": "msg_013gQGh6wysn88YpxAwbb6Jw",
+ "type": "message",
+ "role": "assistant",
+ "model": "claude-3-5-sonnet-20241022",
+ "content": [
+ {
+ "type": "text",
+ "text": "I'll create a website for creating and manipulating 2D objects. Let's call it \"Canvas Play\" - a simple, memorable name that describes its purpose.\n\n---domain---\ncanvasplay.scroll.pub\n\n---index.scroll---\nbuildHtml\nbaseUrl https://canvasplay.scroll.pub\nmetaTags\neditButton /edit.html\ntitle Canvas Play - Interactive 2D Object Manipulator\nstyle.css\nbody.html\nscript.js\n\n---body.html---\n<main class=\"container\">\n <header>\n <h1>Canvas Play</h1>\n <p>Create and manipulate 2D objects</p>\n </header>\n \n <section class=\"controls\">\n <div class=\"shape-controls\">\n <button id=\"addRectangle\" aria-label=\"Add Rectangle\">Rectangle</button>\n <button id=\"addCircle\" aria-label=\"Add Circle\">Circle</button>\n <button id=\"addTriangle\" aria-label=\"Add Triangle\">Triangle</button>\n </div>\n \n <div class=\"color-controls\">\n <input type=\"color\" id=\"colorPicker\" value=\"#ff4444\" aria-label=\"Color picker\">\n <input type=\"range\" id=\"sizeSlider\" min=\"20\" max=\"200\" value=\"50\" aria-label=\"Size slider\">\n </div>\n </section>\n\n <canvas id=\"canvas\" aria-label=\"Drawing canvas\">\n Your browser does not support the canvas element.\n </canvas>\n\n <section class=\"instructions\">\n <h2>Instructions</h2>\n <ul>\n <li>Click buttons to add shapes</li>\n <li>Use arrow keys to move selected shape</li>\n <li>Click a shape to select it</li>\n <li>Press Delete to remove selected shape</li>\n </ul>\n </section>\n</main>\n\n<footer>\n <p>Created with love by Canvas Play</p>\n</footer>\n\n---style.css---\n:root {\n --primary-color: #2c3e50;\n --accent-color: #3498db;\n --bg-color: #ecf0f1;\n --text-color: #2c3e50;\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: var(--bg-color);\n color: var(--text-color);\n line-height: 1.6;\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n}\n\n.container {\n max-width: 1200px;\n margin: 0 auto;\n padding: 2rem;\n}\n\nheader {\n text-align: center;\n margin-bottom: 2rem;\n}\n\nh1 {\n font-size: 2.5rem;\n color: var(--primary-color);\n margin-bottom: 0.5rem;\n text-transform: uppercase;\n letter-spacing: 2px;\n}\n\n.controls {\n display: flex;\n gap: 2rem;\n justify-content: center;\n margin-bottom: 2rem;\n flex-wrap: wrap;\n}\n\nbutton {\n padding: 0.8rem 1.5rem;\n border: none;\n border-radius: 8px;\n background: var(--accent-color);\n color: white;\n cursor: pointer;\n transition: transform 0.2s, background 0.2s;\n}\n\nbutton:hover {\n background: #2980b9;\n transform: translateY(-2px);\n}\n\n#canvas {\n background: white;\n border-radius: 12px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n margin: 0 auto;\n display: block;\n max-width: 100%;\n height: auto;\n}\n\n.instructions {\n margin-top: 2rem;\n padding: 1.5rem;\n background: white;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n\n.instructions h2 {\n margin-bottom: 1rem;\n color: var(--primary-color);\n}\n\n.instructions ul {\n list-style-position: inside;\n color: #666;\n}\n\nfooter {\n margin-top: auto;\n padding: 1rem;\n text-align: center;\n background: var(--primary-color);\n color: white;\n}\n\n@media (max-width: 768px) {\n .container {\n padding: 1rem;\n }\n \n h1 {\n font-size: 2rem;\n }\n \n .controls {\n flex-direction: column;\n align-items: center;\n }\n}\n\n---script.js---\nclass Shape {\n constructor(type, x, y, size, color) {\n this.type = type;\n this.x = x;\n this.y = y;\n this.size = size;\n this.color = color;\n this.selected = false;\n }\n\n draw(ctx) {\n ctx.fillStyle = this.color;\n ctx.strokeStyle = this.selected ? '#2ecc71' : this.color;\n ctx.lineWidth = 3;\n\n switch(this.type) {\n case 'rectangle':\n ctx.fillRect(this.x, this.y, this.size, this.size);\n if (this.selected) {\n ctx.strokeRect(this.x, this.y, this.size, this.size);\n }\n break;\n case 'circle':\n ctx.beginPath();\n ctx.arc(this.x + this.size/2, this.y + this.size/2, this.size/2, 0, Math.PI * 2);\n ctx.fill();\n if (this.selected) {\n ctx.stroke();\n }\n break;\n case 'triangle':\n ctx.beginPath();\n ctx.moveTo(this.x + this.size/2, this.y);\n ctx.lineTo(this.x + this.size, this.y + this.size);\n ctx.lineTo(this.x, this.y + this.size);\n ctx.closePath();\n ctx.fill();\n if (this.selected) {\n ctx.stroke();\n }\n break;\n }\n }\n\n containsPoint(x, y) {\n if (this.type === 'rectangle') {\n return x >= this.x && x <= this.x + this.size &&\n y >= this.y && y <= this.y + this.size;\n } else if (this.type === 'circle') {\n const dx = x - (this.x + this.size/2);\n const dy = y - (this.y + this.size/2);\n return dx * dx + dy * dy <= (this.size/2) * (this.size/2);\n } else if (this.type === 'triangle') {\n // Simple bounding box check for triangle\n return x >= this.x && x <= this.x + this.size &&\n y >= this.y && y <= this.y + this.size;\n }\n return false;\n }\n}\n\ndocument.addEventListener('DOMContentLoaded', () => {\n const canvas = document.getElementById('canvas');\n const ctx = canvas.getContext('2d');\n const shapes = [];\n let selectedShape = null;\n\n // Set canvas size\n function resizeCanvas() {\n canvas.width = Math.min(800, window.innerWidth - 40);\n canvas.height = Math.min(600, window.innerHeight - 200);\n }\n resizeCanvas();\n window.addEventListener('resize', resizeCanvas);\n\n function draw() {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n shapes.forEach(shape => shape.draw(ctx));\n }\n\n function addShape(type) {\n const color = document.getElementById('colorPicker').value;\n const size = parseInt(document.getElementById('sizeSlider').value);\n const x = canvas.width/2 - size/2;\n const y = canvas.height/2 - size/2;\n \n const shape = new Shape(type, x, y, size, color);\n shapes.push(shape);\n selectedShape = shape;\n shapes.forEach(s => s.selected = (s === selectedShape));\n draw();\n }\n\n document.getElementById('addRectangle').addEventListener('click', () => addShape('rectangle'));\n document.getElementById('addCircle').addEventListener('click', () => addShape('circle'));\n document.getElementById('addTriangle').addEventListener('click', () => addShape('triangle'));\n\n canvas.addEventListener('click', (e) => {\n const rect = canvas.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n\n selectedShape = null;\n for (let i = shapes.length - 1; i >= 0; i--) {\n if (shapes[i].containsPoint(x, y)) {\n selectedShape = shapes[i];\n break;\n }\n }\n\n shapes.forEach(shape => shape.selected = (shape === selectedShape));\n draw();\n });\n\n document.addEventListener('keydown', (e) => {\n if (!selectedShape) return;\n\n const step = 10;\n switch(e.key) {\n case 'ArrowLeft':\n selectedShape.x -= step;\n break;\n case 'ArrowRight':\n selectedShape.x += step;\n break;\n case 'ArrowUp':\n selectedShape.y -= step;\n break;\n case 'ArrowDown':\n selectedShape.y += step;\n break;\n case 'Delete':\n const index = shapes.indexOf(selectedShape);\n if (index > -1) {\n shapes.splice(index, 1);\n selectedShape = null;\n }\n break;\n }\n draw();\n });\n\n draw();\n});\n\n---end---\n\nThis website provides a canvas-based interface for creating and manipulating 2D shapes. Users can:\n1. Add rectangles, circles, and triangles\n2. Select colors and sizes\n3. Move shapes with arrow keys\n4. Select shapes by clicking\n5. Delete shapes with the Delete key\n\nThe design is clean and modern, with smooth animations and a responsive layout that works well on both desktop and mobile devices. The code follows best practices for accessibility and performance, using semantic HTML and proper ARIA labels where needed.\n\nThe interface is intuitive and user-friendly, with clear instructions and visual feedback for user interactions. The color scheme is professional and pleasing to the eye, with subtle shadows and transitions that add polish without being overwhelming."
+ }
+ ],
+ "stop_reason": "end_turn",
+ "stop_sequence": null,
+ "usage": {
+ "input_tokens": 299,
+ "cache_creation_input_tokens": 0,
+ "cache_read_input_tokens": 0,
+ "output_tokens": 2749
+ }
+}
\ No newline at end of file
diff --git a/readme.scroll b/readme.scroll
new file mode 100644
index 0000000..c0546b4
--- /dev/null
+++ b/readme.scroll
@@ -0,0 +1,2 @@
+# canvasplay.scroll.pub
+Website generated by Claude from prompt: make a website where you can make and add an 2d objects and manuiplate it and using arrow keys you can move it around
\ No newline at end of file
diff --git a/script.js b/script.js
new file mode 100644
index 0000000..4175ffe
--- /dev/null
+++ b/script.js
@@ -0,0 +1,144 @@
+class Shape {
+ constructor(type, x, y, size, color) {
+ this.type = type;
+ this.x = x;
+ this.y = y;
+ this.size = size;
+ this.color = color;
+ this.selected = false;
+ }
+
+ draw(ctx) {
+ ctx.fillStyle = this.color;
+ ctx.strokeStyle = this.selected ? '#2ecc71' : this.color;
+ ctx.lineWidth = 3;
+
+ switch(this.type) {
+ case 'rectangle':
+ ctx.fillRect(this.x, this.y, this.size, this.size);
+ if (this.selected) {
+ ctx.strokeRect(this.x, this.y, this.size, this.size);
+ }
+ break;
+ case 'circle':
+ ctx.beginPath();
+ ctx.arc(this.x + this.size/2, this.y + this.size/2, this.size/2, 0, Math.PI * 2);
+ ctx.fill();
+ if (this.selected) {
+ ctx.stroke();
+ }
+ break;
+ case 'triangle':
+ ctx.beginPath();
+ ctx.moveTo(this.x + this.size/2, this.y);
+ ctx.lineTo(this.x + this.size, this.y + this.size);
+ ctx.lineTo(this.x, this.y + this.size);
+ ctx.closePath();
+ ctx.fill();
+ if (this.selected) {
+ ctx.stroke();
+ }
+ break;
+ }
+ }
+
+ containsPoint(x, y) {
+ if (this.type === 'rectangle') {
+ return x >= this.x && x <= this.x + this.size &&
+ y >= this.y && y <= this.y + this.size;
+ } else if (this.type === 'circle') {
+ const dx = x - (this.x + this.size/2);
+ const dy = y - (this.y + this.size/2);
+ return dx * dx + dy * dy <= (this.size/2) * (this.size/2);
+ } else if (this.type === 'triangle') {
+ // Simple bounding box check for triangle
+ return x >= this.x && x <= this.x + this.size &&
+ y >= this.y && y <= this.y + this.size;
+ }
+ return false;
+ }
+}
+
+document.addEventListener('DOMContentLoaded', () => {
+ const canvas = document.getElementById('canvas');
+ const ctx = canvas.getContext('2d');
+ const shapes = [];
+ let selectedShape = null;
+
+ // Set canvas size
+ function resizeCanvas() {
+ canvas.width = Math.min(800, window.innerWidth - 40);
+ canvas.height = Math.min(600, window.innerHeight - 200);
+ }
+ resizeCanvas();
+ window.addEventListener('resize', resizeCanvas);
+
+ function draw() {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ shapes.forEach(shape => shape.draw(ctx));
+ }
+
+ function addShape(type) {
+ const color = document.getElementById('colorPicker').value;
+ const size = parseInt(document.getElementById('sizeSlider').value);
+ const x = canvas.width/2 - size/2;
+ const y = canvas.height/2 - size/2;
+
+ const shape = new Shape(type, x, y, size, color);
+ shapes.push(shape);
+ selectedShape = shape;
+ shapes.forEach(s => s.selected = (s === selectedShape));
+ draw();
+ }
+
+ document.getElementById('addRectangle').addEventListener('click', () => addShape('rectangle'));
+ document.getElementById('addCircle').addEventListener('click', () => addShape('circle'));
+ document.getElementById('addTriangle').addEventListener('click', () => addShape('triangle'));
+
+ canvas.addEventListener('click', (e) => {
+ const rect = canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ selectedShape = null;
+ for (let i = shapes.length - 1; i >= 0; i--) {
+ if (shapes[i].containsPoint(x, y)) {
+ selectedShape = shapes[i];
+ break;
+ }
+ }
+
+ shapes.forEach(shape => shape.selected = (shape === selectedShape));
+ draw();
+ });
+
+ document.addEventListener('keydown', (e) => {
+ if (!selectedShape) return;
+
+ const step = 10;
+ switch(e.key) {
+ case 'ArrowLeft':
+ selectedShape.x -= step;
+ break;
+ case 'ArrowRight':
+ selectedShape.x += step;
+ break;
+ case 'ArrowUp':
+ selectedShape.y -= step;
+ break;
+ case 'ArrowDown':
+ selectedShape.y += step;
+ break;
+ case 'Delete':
+ const index = shapes.indexOf(selectedShape);
+ if (index > -1) {
+ shapes.splice(index, 1);
+ selectedShape = null;
+ }
+ break;
+ }
+ draw();
+ });
+
+ draw();
+});
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..69c0df6
--- /dev/null
+++ b/style.css
@@ -0,0 +1,115 @@
+:root {
+ --primary-color: #2c3e50;
+ --accent-color: #3498db;
+ --bg-color: #ecf0f1;
+ --text-color: #2c3e50;
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: 'Segoe UI', system-ui, sans-serif;
+ background: var(--bg-color);
+ color: var(--text-color);
+ line-height: 1.6;
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+}
+
+.container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 2rem;
+}
+
+header {
+ text-align: center;
+ margin-bottom: 2rem;
+}
+
+h1 {
+ font-size: 2.5rem;
+ color: var(--primary-color);
+ margin-bottom: 0.5rem;
+ text-transform: uppercase;
+ letter-spacing: 2px;
+}
+
+.controls {
+ display: flex;
+ gap: 2rem;
+ justify-content: center;
+ margin-bottom: 2rem;
+ flex-wrap: wrap;
+}
+
+button {
+ padding: 0.8rem 1.5rem;
+ border: none;
+ border-radius: 8px;
+ background: var(--accent-color);
+ color: white;
+ cursor: pointer;
+ transition: transform 0.2s, background 0.2s;
+}
+
+button:hover {
+ background: #2980b9;
+ transform: translateY(-2px);
+}
+
+#canvas {
+ background: white;
+ border-radius: 12px;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+ margin: 0 auto;
+ display: block;
+ max-width: 100%;
+ height: auto;
+}
+
+.instructions {
+ margin-top: 2rem;
+ padding: 1.5rem;
+ background: white;
+ border-radius: 8px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.instructions h2 {
+ margin-bottom: 1rem;
+ color: var(--primary-color);
+}
+
+.instructions ul {
+ list-style-position: inside;
+ color: #666;
+}
+
+footer {
+ margin-top: auto;
+ padding: 1rem;
+ text-align: center;
+ background: var(--primary-color);
+ color: white;
+}
+
+@media (max-width: 768px) {
+ .container {
+ padding: 1rem;
+ }
+
+ h1 {
+ font-size: 2rem;
+ }
+
+ .controls {
+ flex-direction: column;
+ align-items: center;
+ }
+}