Changes to shapescape.scroll.pub

root
root
26 days ago
Initial commit
body.html
Changed around line 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
index.scroll
Changed around line 1
+ buildHtml
+ baseUrl https://shapescape.scroll.pub
+ metaTags
+ editButton /edit.html
+ title ShapeScape - Create & Edit SVG Shapes
+ style.css
+ body.html
+ script.js
prompt.json
Changed around line 1
+ {
+ "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
\n
\n \n \n \n \n
\n\n \n\n
\n \n \n \n
\n
\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"
+ }
readme.scroll
Changed around line 1
+ # 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
script.js
Changed around line 1
+ 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;
+ });
style.css
Changed around line 1
+ :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%;
+ }
+ }