commit 6bb20db3375bc22e60b917e932c4936e51f4b64e
Author: root <root@hub.scroll.pub>
Date: 2024-12-27 19:24:15 +0000
Subject: Initial commit
diff --git a/body.html b/body.html
new file mode 100644
index 0000000..31d5f54
--- /dev/null
+++ b/body.html
@@ -0,0 +1,33 @@
+<div class="app-container">
+ <header class="toolbar">
+ <select id="stroke-color">
+ <option value="#000000">Black</option>
+ <option value="#ff0000">Red</option>
+ <option value="#00ff00">Green</option>
+ <option value="#0000ff">Blue</option>
+ </select>
+ <select id="fill-color">
+ <option value="none">None</option>
+ <option value="#ffffff">White</option>
+ <option value="#ffcccc">Light Red</option>
+ <option value="#ccffcc">Light Green</option>
+ <option value="#ccccff">Light Blue</option>
+ </select>
+ <input type="number" id="stroke-width" min="1" max="10" value="2">
+ <button id="delete-shape">Delete</button>
+ </header>
+
+ <aside class="sidebar">
+ <button class="shape-btn" data-type="line">Add Line</button>
+ <button class="shape-btn" data-type="rect">Add Rectangle</button>
+ <button class="shape-btn" data-type="triangle">Add Triangle</button>
+ <button class="shape-btn" data-type="ellipse">Add Ellipse</button>
+ <button class="shape-btn" data-type="text">Add Text</button>
+ </aside>
+
+ <main class="canvas-container">
+ <svg id="main-canvas" viewBox="0 0 800 600" xmlns="http://www.w3.org/2000/svg">
+ <!-- Shapes will be added here -->
+ </svg>
+ </main>
+</div>
\ No newline at end of file
diff --git a/index.scroll b/index.scroll
new file mode 100644
index 0000000..6a21d04
--- /dev/null
+++ b/index.scroll
@@ -0,0 +1,8 @@
+buildHtml
+baseUrl https://shapescape.scroll.pub
+metaTags
+editButton /edit.html
+title ShapeScape - Create & Edit SVG Shapes
+style.css
+body.html
+script.js
\ No newline at end of file
diff --git a/prompt.json b/prompt.json
new file mode 100644
index 0000000..427da88
--- /dev/null
+++ b/prompt.json
@@ -0,0 +1,25 @@
+{
+ "id": "4b81891f-48c5-44d7-8afc-283b52ae4e44",
+ "object": "chat.completion",
+ "created": 1735327431,
+ "model": "deepseek-chat",
+ "choices": [
+ {
+ "index": 0,
+ "message": {
+ "role": "assistant",
+ "content": "---domain---\nshapescape.scroll.pub\n---index.scroll---\nbuildHtml\nbaseUrl https://shapescape.scroll.pub\nmetaTags\neditButton /edit.html\ntitle ShapeScape - Create & Edit SVG Shapes\nstyle.css\nbody.html\nscript.js\n---body.html---\n<div class=\"app-container\">\n <header class=\"toolbar\">\n <select id=\"stroke-color\">\n <option value=\"#000000\">Black</option>\n <option value=\"#ff0000\">Red</option>\n <option value=\"#00ff00\">Green</option>\n <option value=\"#0000ff\">Blue</option>\n </select>\n <select id=\"fill-color\">\n <option value=\"none\">None</option>\n <option value=\"#ffffff\">White</option>\n <option value=\"#ffcccc\">Light Red</option>\n <option value=\"#ccffcc\">Light Green</option>\n <option value=\"#ccccff\">Light Blue</option>\n </select>\n <input type=\"number\" id=\"stroke-width\" min=\"1\" max=\"10\" value=\"2\">\n <button id=\"delete-shape\">Delete</button>\n </header>\n\n <aside class=\"sidebar\">\n <button class=\"shape-btn\" data-type=\"line\">Add Line</button>\n <button class=\"shape-btn\" data-type=\"rect\">Add Rectangle</button>\n <button class=\"shape-btn\" data-type=\"triangle\">Add Triangle</button>\n <button class=\"shape-btn\" data-type=\"ellipse\">Add Ellipse</button>\n <button class=\"shape-btn\" data-type=\"text\">Add Text</button>\n </aside>\n\n <main class=\"canvas-container\">\n <svg id=\"main-canvas\" viewBox=\"0 0 800 600\" xmlns=\"http://www.w3.org/2000/svg\">\n <!-- Shapes will be added here -->\n </svg>\n </main>\n</div>\n---style.css---\n:root {\n --primary-color: #4a90e2;\n --secondary-color: #f5f5f5;\n --border-color: #ddd;\n --hover-color: #e0e0e0;\n}\n\n* {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\nbody {\n font-family: 'Segoe UI', system-ui, sans-serif;\n min-height: 100vh;\n display: flex;\n background-color: var(--secondary-color);\n}\n\n.app-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n min-height: 100vh;\n}\n\n.toolbar {\n display: flex;\n gap: 1rem;\n padding: 1rem;\n background-color: white;\n border-bottom: 1px solid var(--border-color);\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n}\n\n.sidebar {\n width: 200px;\n background-color: white;\n border-right: 1px solid var(--border-color);\n padding: 1rem;\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.shape-btn {\n padding: 0.75rem;\n background-color: var(--primary-color);\n color: white;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n transition: background-color 0.2s;\n}\n\n.shape-btn:hover {\n background-color: darken(var(--primary-color), 10%);\n}\n\n.canvas-container {\n flex: 1;\n position: relative;\n overflow: hidden;\n}\n\n#main-canvas {\n width: 100%;\n height: 100%;\n background-color: white;\n touch-action: none;\n}\n\n@media (max-width: 768px) {\n .app-container {\n flex-direction: column;\n }\n \n .sidebar {\n width: 100%;\n flex-direction: row;\n flex-wrap: wrap;\n border-right: none;\n border-bottom: 1px solid var(--border-color);\n }\n \n .shape-btn {\n flex: 1 1 45%;\n }\n}\n---script.js---\nlet selectedShape = null;\nlet isDragging = false;\nlet startX, startY;\nlet currentScale = 1;\nlet panOffset = { x: 0, y: 0 };\n\nconst canvas = document.getElementById('main-canvas');\nconst shapeButtons = document.querySelectorAll('.shape-btn');\nconst strokeColor = document.getElementById('stroke-color');\nconst fillColor = document.getElementById('fill-color');\nconst strokeWidth = document.getElementById('stroke-width');\nconst deleteButton = document.getElementById('delete-shape');\n\n// Add shape event listeners\nshapeButtons.forEach(button => {\n button.addEventListener('click', () => {\n const type = button.dataset.type;\n addShape(type);\n });\n});\n\n// Add shape to canvas\nfunction addShape(type) {\n const shape = document.createElementNS('http://www.w3.org/2000/svg', type);\n shape.setAttribute('stroke', strokeColor.value);\n shape.setAttribute('fill', fillColor.value === 'none' ? 'none' : fillColor.value);\n shape.setAttribute('stroke-width', strokeWidth.value);\n \n // Set initial position and size based on shape type\n switch(type) {\n case 'line':\n shape.setAttribute('x1', 100);\n shape.setAttribute('y1', 100);\n shape.setAttribute('x2', 200);\n shape.setAttribute('y2', 200);\n break;\n case 'rect':\n shape.setAttribute('x', 100);\n shape.setAttribute('y', 100);\n shape.setAttribute('width', 100);\n shape.setAttribute('height', 100);\n break;\n case 'triangle':\n shape.setAttribute('points', '150,50 100,150 200,150');\n break;\n case 'ellipse':\n shape.setAttribute('cx', 150);\n shape.setAttribute('cy', 100);\n shape.setAttribute('rx', 50);\n shape.setAttribute('ry', 30);\n break;\n case 'text':\n shape.setAttribute('x', 100);\n shape.setAttribute('y', 100);\n shape.textContent = 'Text';\n break;\n }\n\n shape.addEventListener('click', (e) => {\n e.stopPropagation();\n selectShape(shape);\n });\n\n canvas.appendChild(shape);\n selectShape(shape);\n}\n\n// Select shape\nfunction selectShape(shape) {\n if (selectedShape) {\n selectedShape.classList.remove('selected');\n }\n selectedShape = shape;\n selectedShape.classList.add('selected');\n}\n\n// Delete selected shape\ndeleteButton.addEventListener('click', () => {\n if (selectedShape) {\n canvas.removeChild(selectedShape);\n selectedShape = null;\n }\n});\n\n// Pan and zoom functionality\ncanvas.addEventListener('wheel', (e) => {\n e.preventDefault();\n const scaleFactor = 1.1;\n const rect = canvas.getBoundingClientRect();\n const offsetX = e.clientX - rect.left;\n const offsetY = e.clientY - rect.top;\n \n if (e.deltaY < 0) {\n currentScale *= scaleFactor;\n } else {\n currentScale /= scaleFactor;\n }\n \n canvas.style.transform = `scale(${currentScale})`;\n panOffset.x = offsetX - (offsetX - panOffset.x) * (e.deltaY < 0 ? scaleFactor : 1/scaleFactor);\n panOffset.y = offsetY - (offsetY - panOffset.y) * (e.deltaY < 0 ? scaleFactor : 1/scaleFactor);\n canvas.style.transformOrigin = `${panOffset.x}px ${panOffset.y}px`;\n});\n\ncanvas.addEventListener('mousedown', (e) => {\n if (e.target === canvas) {\n isDragging = true;\n startX = e.clientX - panOffset.x;\n startY = e.clientY - panOffset.y;\n }\n});\n\ncanvas.addEventListener('mousemove', (e) => {\n if (isDragging) {\n panOffset.x = e.clientX - startX;\n panOffset.y = e.clientY - startY;\n canvas.style.transform = `translate(${panOffset.x}px, ${panOffset.y}px) scale(${currentScale})`;\n }\n});\n\ncanvas.addEventListener('mouseup', () => {\n isDragging = false;\n});\n\ncanvas.addEventListener('mouseleave', () => {\n isDragging = false;\n});\n---end---"
+ },
+ "logprobs": null,
+ "finish_reason": "stop"
+ }
+ ],
+ "usage": {
+ "prompt_tokens": 312,
+ "completion_tokens": 1853,
+ "total_tokens": 2165,
+ "prompt_cache_hit_tokens": 0,
+ "prompt_cache_miss_tokens": 312
+ },
+ "system_fingerprint": "fp_f1afce2943"
+}
\ No newline at end of file
diff --git a/readme.scroll b/readme.scroll
new file mode 100644
index 0000000..727dc5c
--- /dev/null
+++ b/readme.scroll
@@ -0,0 +1,2 @@
+# shapescape.scroll.pub
+Website generated by DeepSeek from prompt: I want an svg canvas that you can pan and zoom. In the left sidebar have a series of buttons that add shapes (line, rectangle, triangle, ellipse, text box) to the canvas. When added to the canvas, the shapes can be selected, moved and resized. At the top, have some select boxes and buttons in a toolbar to change the properties of the shapes
\ No newline at end of file
diff --git a/script.js b/script.js
new file mode 100644
index 0000000..ff44c53
--- /dev/null
+++ b/script.js
@@ -0,0 +1,127 @@
+let selectedShape = null;
+let isDragging = false;
+let startX, startY;
+let currentScale = 1;
+let panOffset = { x: 0, y: 0 };
+
+const canvas = document.getElementById('main-canvas');
+const shapeButtons = document.querySelectorAll('.shape-btn');
+const strokeColor = document.getElementById('stroke-color');
+const fillColor = document.getElementById('fill-color');
+const strokeWidth = document.getElementById('stroke-width');
+const deleteButton = document.getElementById('delete-shape');
+
+// Add shape event listeners
+shapeButtons.forEach(button => {
+ button.addEventListener('click', () => {
+ const type = button.dataset.type;
+ addShape(type);
+ });
+});
+
+// Add shape to canvas
+function addShape(type) {
+ const shape = document.createElementNS('http://www.w3.org/2000/svg', type);
+ shape.setAttribute('stroke', strokeColor.value);
+ shape.setAttribute('fill', fillColor.value === 'none' ? 'none' : fillColor.value);
+ shape.setAttribute('stroke-width', strokeWidth.value);
+
+ // Set initial position and size based on shape type
+ switch(type) {
+ case 'line':
+ shape.setAttribute('x1', 100);
+ shape.setAttribute('y1', 100);
+ shape.setAttribute('x2', 200);
+ shape.setAttribute('y2', 200);
+ break;
+ case 'rect':
+ shape.setAttribute('x', 100);
+ shape.setAttribute('y', 100);
+ shape.setAttribute('width', 100);
+ shape.setAttribute('height', 100);
+ break;
+ case 'triangle':
+ shape.setAttribute('points', '150,50 100,150 200,150');
+ break;
+ case 'ellipse':
+ shape.setAttribute('cx', 150);
+ shape.setAttribute('cy', 100);
+ shape.setAttribute('rx', 50);
+ shape.setAttribute('ry', 30);
+ break;
+ case 'text':
+ shape.setAttribute('x', 100);
+ shape.setAttribute('y', 100);
+ shape.textContent = 'Text';
+ break;
+ }
+
+ shape.addEventListener('click', (e) => {
+ e.stopPropagation();
+ selectShape(shape);
+ });
+
+ canvas.appendChild(shape);
+ selectShape(shape);
+}
+
+// Select shape
+function selectShape(shape) {
+ if (selectedShape) {
+ selectedShape.classList.remove('selected');
+ }
+ selectedShape = shape;
+ selectedShape.classList.add('selected');
+}
+
+// Delete selected shape
+deleteButton.addEventListener('click', () => {
+ if (selectedShape) {
+ canvas.removeChild(selectedShape);
+ selectedShape = null;
+ }
+});
+
+// Pan and zoom functionality
+canvas.addEventListener('wheel', (e) => {
+ e.preventDefault();
+ const scaleFactor = 1.1;
+ const rect = canvas.getBoundingClientRect();
+ const offsetX = e.clientX - rect.left;
+ const offsetY = e.clientY - rect.top;
+
+ if (e.deltaY < 0) {
+ currentScale *= scaleFactor;
+ } else {
+ currentScale /= scaleFactor;
+ }
+
+ canvas.style.transform = `scale(${currentScale})`;
+ panOffset.x = offsetX - (offsetX - panOffset.x) * (e.deltaY < 0 ? scaleFactor : 1/scaleFactor);
+ panOffset.y = offsetY - (offsetY - panOffset.y) * (e.deltaY < 0 ? scaleFactor : 1/scaleFactor);
+ canvas.style.transformOrigin = `${panOffset.x}px ${panOffset.y}px`;
+});
+
+canvas.addEventListener('mousedown', (e) => {
+ if (e.target === canvas) {
+ isDragging = true;
+ startX = e.clientX - panOffset.x;
+ startY = e.clientY - panOffset.y;
+ }
+});
+
+canvas.addEventListener('mousemove', (e) => {
+ if (isDragging) {
+ panOffset.x = e.clientX - startX;
+ panOffset.y = e.clientY - startY;
+ canvas.style.transform = `translate(${panOffset.x}px, ${panOffset.y}px) scale(${currentScale})`;
+ }
+});
+
+canvas.addEventListener('mouseup', () => {
+ isDragging = false;
+});
+
+canvas.addEventListener('mouseleave', () => {
+ isDragging = false;
+});
\ No newline at end of file
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..b609743
--- /dev/null
+++ b/style.css
@@ -0,0 +1,90 @@
+:root {
+ --primary-color: #4a90e2;
+ --secondary-color: #f5f5f5;
+ --border-color: #ddd;
+ --hover-color: #e0e0e0;
+}
+
+* {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ font-family: 'Segoe UI', system-ui, sans-serif;
+ min-height: 100vh;
+ display: flex;
+ background-color: var(--secondary-color);
+}
+
+.app-container {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ min-height: 100vh;
+}
+
+.toolbar {
+ display: flex;
+ gap: 1rem;
+ padding: 1rem;
+ background-color: white;
+ border-bottom: 1px solid var(--border-color);
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+}
+
+.sidebar {
+ width: 200px;
+ background-color: white;
+ border-right: 1px solid var(--border-color);
+ padding: 1rem;
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+}
+
+.shape-btn {
+ padding: 0.75rem;
+ background-color: var(--primary-color);
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ transition: background-color 0.2s;
+}
+
+.shape-btn:hover {
+ background-color: darken(var(--primary-color), 10%);
+}
+
+.canvas-container {
+ flex: 1;
+ position: relative;
+ overflow: hidden;
+}
+
+#main-canvas {
+ width: 100%;
+ height: 100%;
+ background-color: white;
+ touch-action: none;
+}
+
+@media (max-width: 768px) {
+ .app-container {
+ flex-direction: column;
+ }
+
+ .sidebar {
+ width: 100%;
+ flex-direction: row;
+ flex-wrap: wrap;
+ border-right: none;
+ border-bottom: 1px solid var(--border-color);
+ }
+
+ .shape-btn {
+ flex: 1 1 45%;
+ }
+}
\ No newline at end of file