MarkTheArtist commited on
Commit
3f07217
·
verified ·
1 Parent(s): ee81f70

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +1023 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Svg Creator
3
- emoji: 🔥
4
- colorFrom: gray
5
- colorTo: pink
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: svg-creator
3
+ emoji: 🐳
4
+ colorFrom: purple
5
+ colorTo: gray
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1023 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>SVG Path Editor</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdn.jsdelivr.net/npm/svg-path-editor@1.0.0/dist/index.min.js"></script>
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
+ <style>
11
+ .path-point {
12
+ position: absolute;
13
+ width: 10px;
14
+ height: 10px;
15
+ background-color: #3b82f6;
16
+ border-radius: 50%;
17
+ transform: translate(-50%, -50%);
18
+ cursor: move;
19
+ z-index: 10;
20
+ }
21
+ .path-point.active {
22
+ background-color: #ef4444;
23
+ width: 12px;
24
+ height: 12px;
25
+ }
26
+ .control-point {
27
+ position: absolute;
28
+ width: 8px;
29
+ height: 8px;
30
+ background-color: #10b981;
31
+ border-radius: 50%;
32
+ transform: translate(-50%, -50%);
33
+ cursor: move;
34
+ z-index: 5;
35
+ }
36
+ .control-line {
37
+ position: absolute;
38
+ background-color: rgba(75, 85, 99, 0.3);
39
+ height: 1px;
40
+ transform-origin: left center;
41
+ z-index: 2;
42
+ }
43
+ #svgCanvas {
44
+ border: 1px dashed #94a3b8;
45
+ background-color: #f8fafc;
46
+ background-image:
47
+ linear-gradient(to right, rgba(0,0,0,0.05) 1px, transparent 1px),
48
+ linear-gradient(to bottom, rgba(0,0,0,0.05) 1px, transparent 1px);
49
+ background-size: 20px 20px;
50
+ }
51
+ .tool-btn.active {
52
+ background-color: #3b82f6;
53
+ color: white;
54
+ }
55
+ .command-btn.active {
56
+ background-color: #10b981;
57
+ color: white;
58
+ }
59
+ #helpModal {
60
+ transition: opacity 0.3s ease, transform 0.3s ease;
61
+ }
62
+ #helpModal.hidden {
63
+ opacity: 0;
64
+ transform: translateY(-20px);
65
+ pointer-events: none;
66
+ }
67
+ </style>
68
+ </head>
69
+ <body class="bg-gray-50 min-h-screen">
70
+ <div class="container mx-auto px-4 py-8">
71
+ <header class="mb-8 flex justify-between items-start">
72
+ <div>
73
+ <h1 class="text-3xl font-bold text-gray-800">SVG Path Editor</h1>
74
+ <p class="text-gray-600">Create and edit SVG paths visually with real-time code output</p>
75
+ </div>
76
+ <button id="helpButton" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg transition flex items-center">
77
+ <i class="fas fa-question-circle mr-2"></i> Help
78
+ </button>
79
+ </header>
80
+
81
+ <!-- Help Modal -->
82
+ <div id="helpModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50 hidden">
83
+ <div class="bg-white rounded-lg shadow-xl max-w-2xl w-full max-h-[90vh] overflow-y-auto">
84
+ <div class="p-6">
85
+ <div class="flex justify-between items-center mb-4">
86
+ <h2 class="text-2xl font-bold text-gray-800">SVG Path Editor Help</h2>
87
+ <button id="closeHelp" class="text-gray-500 hover:text-gray-700">
88
+ <i class="fas fa-times text-xl"></i>
89
+ </button>
90
+ </div>
91
+
92
+ <div class="space-y-6">
93
+ <div>
94
+ <h3 class="text-lg font-semibold text-gray-800 mb-2">Tools</h3>
95
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
96
+ <div class="bg-gray-50 p-3 rounded-lg">
97
+ <div class="flex items-center mb-2">
98
+ <div class="bg-blue-100 text-blue-800 p-2 rounded-full mr-3">
99
+ <i class="fas fa-mouse-pointer"></i>
100
+ </div>
101
+ <h4 class="font-medium">Select Tool</h4>
102
+ </div>
103
+ <p class="text-gray-600 text-sm">Click to select points. Drag to move them. Shows control points for curves.</p>
104
+ </div>
105
+ <div class="bg-gray-50 p-3 rounded-lg">
106
+ <div class="flex items-center mb-2">
107
+ <div class="bg-blue-100 text-blue-800 p-2 rounded-full mr-3">
108
+ <i class="fas fa-pen"></i>
109
+ </div>
110
+ <h4 class="font-medium">Pen Tool</h4>
111
+ </div>
112
+ <p class="text-gray-600 text-sm">Click to add new points to your path. Uses the currently selected command.</p>
113
+ </div>
114
+ <div class="bg-gray-50 p-3 rounded-lg">
115
+ <div class="flex items-center mb-2">
116
+ <div class="bg-blue-100 text-blue-800 p-2 rounded-full mr-3">
117
+ <i class="fas fa-arrows-alt"></i>
118
+ </div>
119
+ <h4 class="font-medium">Move Tool</h4>
120
+ </div>
121
+ <p class="text-gray-600 text-sm">Click and drag to move the entire path around the canvas.</p>
122
+ </div>
123
+ <div class="bg-gray-50 p-3 rounded-lg">
124
+ <div class="flex items-center mb-2">
125
+ <div class="bg-blue-100 text-blue-800 p-2 rounded-full mr-3">
126
+ <i class="fas fa-trash"></i>
127
+ </div>
128
+ <h4 class="font-medium">Delete Tool</h4>
129
+ </div>
130
+ <p class="text-gray-600 text-sm">Click on points to remove them from your path.</p>
131
+ </div>
132
+ </div>
133
+ </div>
134
+
135
+ <div>
136
+ <h3 class="text-lg font-semibold text-gray-800 mb-2">Path Commands</h3>
137
+ <div class="grid grid-cols-2 md:grid-cols-3 gap-3">
138
+ <div class="bg-gray-50 p-3 rounded-lg">
139
+ <div class="flex items-center mb-1">
140
+ <span class="bg-green-100 text-green-800 px-2 py-1 rounded text-sm font-mono mr-2">M</span>
141
+ <h4 class="font-medium">Move To</h4>
142
+ </div>
143
+ <p class="text-gray-600 text-sm">Starts a new sub-path at the given coordinates.</p>
144
+ </div>
145
+ <div class="bg-gray-50 p-3 rounded-lg">
146
+ <div class="flex items-center mb-1">
147
+ <span class="bg-green-100 text-green-800 px-2 py-1 rounded text-sm font-mono mr-2">L</span>
148
+ <h4 class="font-medium">Line To</h4>
149
+ </div>
150
+ <p class="text-gray-600 text-sm">Draws a straight line to the given coordinates.</p>
151
+ </div>
152
+ <div class="bg-gray-50 p-3 rounded-lg">
153
+ <div class="flex items-center mb-1">
154
+ <span class="bg-green-100 text-green-800 px-2 py-1 rounded text-sm font-mono mr-2">H</span>
155
+ <h4 class="font-medium">Horizontal Line</h4>
156
+ </div>
157
+ <p class="text-gray-600 text-sm">Draws a horizontal line to the given x coordinate.</p>
158
+ </div>
159
+ <div class="bg-gray-50 p-3 rounded-lg">
160
+ <div class="flex items-center mb-1">
161
+ <span class="bg-green-100 text-green-800 px-2 py-1 rounded text-sm font-mono mr-2">V</span>
162
+ <h4 class="font-medium">Vertical Line</h4>
163
+ </div>
164
+ <p class="text-gray-600 text-sm">Draws a vertical line to the given y coordinate.</p>
165
+ </div>
166
+ <div class="bg-gray-50 p-3 rounded-lg">
167
+ <div class="flex items-center mb-1">
168
+ <span class="bg-green-100 text-green-800 px-2 py-1 rounded text-sm font-mono mr-2">C</span>
169
+ <h4 class="font-medium">Cubic Bézier</h4>
170
+ </div>
171
+ <p class="text-gray-600 text-sm">Draws a cubic Bézier curve with two control points.</p>
172
+ </div>
173
+ <div class="bg-gray-50 p-3 rounded-lg">
174
+ <div class="flex items-center mb-1">
175
+ <span class="bg-green-100 text-green-800 px-2 py-1 rounded text-sm font-mono mr-2">Q</span>
176
+ <h4 class="font-medium">Quadratic Bézier</h4>
177
+ </div>
178
+ <p class="text-gray-600 text-sm">Draws a quadratic Bézier curve with one control point.</p>
179
+ </div>
180
+ <div class="bg-gray-50 p-3 rounded-lg">
181
+ <div class="flex items-center mb-1">
182
+ <span class="bg-green-100 text-green-800 px-2 py-1 rounded text-sm font-mono mr-2">Z</span>
183
+ <h4 class="font-medium">Close Path</h4>
184
+ </div>
185
+ <p class="text-gray-600 text-sm">Closes the current sub-path with a straight line.</p>
186
+ </div>
187
+ </div>
188
+ </div>
189
+
190
+ <div>
191
+ <h3 class="text-lg font-semibold text-gray-800 mb-2">Controls</h3>
192
+ <div class="space-y-3">
193
+ <div class="bg-gray-50 p-3 rounded-lg">
194
+ <h4 class="font-medium mb-1">Stroke & Fill</h4>
195
+ <p class="text-gray-600 text-sm">Change the appearance of your path with color pickers and stroke width slider.</p>
196
+ </div>
197
+ <div class="bg-gray-50 p-3 rounded-lg">
198
+ <h4 class="font-medium mb-1">Zoom</h4>
199
+ <p class="text-gray-600 text-sm">Adjust the zoom level to work on fine details or see the big picture.</p>
200
+ </div>
201
+ <div class="bg-gray-50 p-3 rounded-lg">
202
+ <h4 class="font-medium mb-1">Clear & Download</h4>
203
+ <p class="text-gray-600 text-sm">Start fresh with Clear or download your creation as an SVG file.</p>
204
+ </div>
205
+ <div class="bg-gray-50 p-3 rounded-lg">
206
+ <h4 class="font-medium mb-1">Path Data</h4>
207
+ <p class="text-gray-600 text-sm">The generated SVG path data is shown below the canvas and can be copied.</p>
208
+ </div>
209
+ </div>
210
+ </div>
211
+
212
+ <div class="bg-blue-50 border border-blue-100 p-4 rounded-lg">
213
+ <h4 class="font-semibold text-blue-800 mb-2">Tips & Tricks</h4>
214
+ <ul class="text-blue-700 text-sm space-y-2">
215
+ <li class="flex items-start">
216
+ <span class="bg-blue-200 rounded-full p-1 mr-2">
217
+ <i class="fas fa-lightbulb text-xs"></i>
218
+ </span>
219
+ <span>Hold Shift while dragging to constrain movement to horizontal/vertical</span>
220
+ </li>
221
+ <li class="flex items-start">
222
+ <span class="bg-blue-200 rounded-full p-1 mr-2">
223
+ <i class="fas fa-lightbulb text-xs"></i>
224
+ </span>
225
+ <span>Double-click a point to change its command type</span>
226
+ </li>
227
+ <li class="flex items-start">
228
+ <span class="bg-blue-200 rounded-full p-1 mr-2">
229
+ <i class="fas fa-lightbulb text-xs"></i>
230
+ </span>
231
+ <span>Use the Properties panel to precisely position points</span>
232
+ </li>
233
+ </ul>
234
+ </div>
235
+ </div>
236
+ </div>
237
+ </div>
238
+ </div>
239
+
240
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
241
+ <!-- Tools Panel -->
242
+ <div class="bg-white rounded-lg shadow p-4 lg:col-span-1">
243
+ <h2 class="text-xl font-semibold mb-4 text-gray-800">Tools</h2>
244
+
245
+ <div class="grid grid-cols-4 gap-2 mb-6">
246
+ <button id="selectTool" class="tool-btn active p-2 rounded hover:bg-gray-200 transition">
247
+ <i class="fas fa-mouse-pointer"></i>
248
+ </button>
249
+ <button id="penTool" class="tool-btn p-2 rounded hover:bg-gray-200 transition">
250
+ <i class="fas fa-pen"></i>
251
+ </button>
252
+ <button id="moveTool" class="tool-btn p-2 rounded hover:bg-gray-200 transition">
253
+ <i class="fas fa-arrows-alt"></i>
254
+ </button>
255
+ <button id="deleteTool" class="tool-btn p-2 rounded hover:bg-gray-200 transition">
256
+ <i class="fas fa-trash"></i>
257
+ </button>
258
+ </div>
259
+
260
+ <h3 class="font-medium mb-2 text-gray-700">Path Commands</h3>
261
+ <div class="grid grid-cols-3 gap-2 mb-6">
262
+ <button data-command="M" class="command-btn p-2 rounded hover:bg-gray-200 transition">M</button>
263
+ <button data-command="L" class="command-btn p-2 rounded hover:bg-gray-200 transition">L</button>
264
+ <button data-command="H" class="command-btn p-2 rounded hover:bg-gray-200 transition">H</button>
265
+ <button data-command="V" class="command-btn p-2 rounded hover:bg-gray-200 transition">V</button>
266
+ <button data-command="C" class="command-btn p-2 rounded hover:bg-gray-200 transition">C</button>
267
+ <button data-command="Q" class="command-btn p-2 rounded hover:bg-gray-200 transition">Q</button>
268
+ <button data-command="Z" class="command-btn p-2 rounded hover:bg-gray-200 transition">Z</button>
269
+ </div>
270
+
271
+ <div class="mb-4">
272
+ <label class="block text-sm font-medium text-gray-700 mb-1">Stroke Color</label>
273
+ <input type="color" id="strokeColor" value="#3b82f6" class="w-full h-10">
274
+ </div>
275
+
276
+ <div class="mb-4">
277
+ <label class="block text-sm font-medium text-gray-700 mb-1">Stroke Width</label>
278
+ <input type="range" id="strokeWidth" min="1" max="10" value="2" class="w-full">
279
+ </div>
280
+
281
+ <div class="mb-4">
282
+ <label class="block text-sm font-medium text-gray-700 mb-1">Fill Color</label>
283
+ <input type="color" id="fillColor" value="#93c5fd" class="w-full h-10">
284
+ </div>
285
+
286
+ <div class="flex space-x-2">
287
+ <button id="clearPath" class="bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded transition">
288
+ Clear
289
+ </button>
290
+ <button id="downloadSVG" class="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded transition">
291
+ Download SVG
292
+ </button>
293
+ </div>
294
+ </div>
295
+
296
+ <!-- Canvas Area -->
297
+ <div class="bg-white rounded-lg shadow p-4 lg:col-span-2">
298
+ <div class="flex justify-between items-center mb-4">
299
+ <h2 class="text-xl font-semibold text-gray-800">Canvas</h2>
300
+ <div class="flex items-center space-x-2">
301
+ <span class="text-sm text-gray-600">Zoom:</span>
302
+ <select id="zoomLevel" class="border rounded px-2 py-1 text-sm">
303
+ <option value="0.5">50%</option>
304
+ <option value="0.75">75%</option>
305
+ <option value="1" selected>100%</option>
306
+ <option value="1.5">150%</option>
307
+ <option value="2">200%</option>
308
+ </select>
309
+ </div>
310
+ </div>
311
+
312
+ <div class="relative overflow-auto border rounded-lg bg-white mb-4">
313
+ <div id="svgContainer" class="relative overflow-auto">
314
+ <svg id="svgCanvas" width="600" height="400" viewBox="0 0 600 400"></svg>
315
+ </div>
316
+ </div>
317
+
318
+ <div class="bg-gray-50 p-3 rounded border">
319
+ <div class="flex justify-between items-center mb-2">
320
+ <h3 class="font-medium text-gray-700">Path Data</h3>
321
+ <button id="copyPath" class="text-sm bg-gray-200 hover:bg-gray-300 px-2 py-1 rounded transition">
322
+ <i class="fas fa-copy mr-1"></i> Copy
323
+ </button>
324
+ </div>
325
+ <textarea id="pathData" class="w-full h-24 p-2 border rounded font-mono text-sm bg-white" readonly></textarea>
326
+ </div>
327
+ </div>
328
+ </div>
329
+
330
+ <!-- Properties Panel (hidden by default) -->
331
+ <div id="propertiesPanel" class="hidden mt-6 bg-white rounded-lg shadow p-4">
332
+ <h2 class="text-xl font-semibold mb-4 text-gray-800">Point Properties</h2>
333
+ <div class="grid grid-cols-2 gap-4">
334
+ <div>
335
+ <label class="block text-sm font-medium text-gray-700 mb-1">X Position</label>
336
+ <input type="number" id="pointX" class="w-full border rounded px-2 py-1">
337
+ </div>
338
+ <div>
339
+ <label class="block text-sm font-medium text-gray-700 mb-1">Y Position</label>
340
+ <input type="number" id="pointY" class="w-full border rounded px-2 py-1">
341
+ </div>
342
+ </div>
343
+ </div>
344
+ </div>
345
+
346
+ <script>
347
+ document.addEventListener('DOMContentLoaded', function() {
348
+ // Canvas setup
349
+ const svgCanvas = document.getElementById('svgCanvas');
350
+ const svgContainer = document.getElementById('svgContainer');
351
+ const pathData = document.getElementById('pathData');
352
+ const zoomLevel = document.getElementById('zoomLevel');
353
+
354
+ // Help modal elements
355
+ const helpButton = document.getElementById('helpButton');
356
+ const helpModal = document.getElementById('helpModal');
357
+ const closeHelp = document.getElementById('closeHelp');
358
+
359
+ // Help modal functionality
360
+ helpButton.addEventListener('click', function() {
361
+ helpModal.classList.remove('hidden');
362
+ });
363
+
364
+ closeHelp.addEventListener('click', function() {
365
+ helpModal.classList.add('hidden');
366
+ });
367
+
368
+ // Close modal when clicking outside
369
+ helpModal.addEventListener('click', function(e) {
370
+ if (e.target === helpModal) {
371
+ helpModal.classList.add('hidden');
372
+ }
373
+ });
374
+
375
+ let currentPath = null;
376
+ let currentPoints = [];
377
+ let currentControlPoints = [];
378
+ let currentControlLines = [];
379
+ let activePoint = null;
380
+ let activeCommand = 'M';
381
+ let currentTool = 'select';
382
+
383
+ // Initialize with empty path
384
+ resetPath();
385
+
386
+ // Tool buttons
387
+ document.querySelectorAll('.tool-btn').forEach(btn => {
388
+ btn.addEventListener('click', function() {
389
+ document.querySelectorAll('.tool-btn').forEach(b => b.classList.remove('active'));
390
+ this.classList.add('active');
391
+ currentTool = this.id.replace('Tool', '').toLowerCase();
392
+ });
393
+ });
394
+
395
+ // Command buttons
396
+ document.querySelectorAll('.command-btn').forEach(btn => {
397
+ btn.addEventListener('click', function() {
398
+ document.querySelectorAll('.command-btn').forEach(b => b.classList.remove('active'));
399
+ this.classList.add('active');
400
+ activeCommand = this.dataset.command;
401
+ });
402
+ });
403
+
404
+ // Color pickers
405
+ document.getElementById('strokeColor').addEventListener('input', updatePathStyle);
406
+ document.getElementById('fillColor').addEventListener('input', updatePathStyle);
407
+ document.getElementById('strokeWidth').addEventListener('input', updatePathStyle);
408
+
409
+ // Clear button
410
+ document.getElementById('clearPath').addEventListener('click', resetPath);
411
+
412
+ // Download button
413
+ document.getElementById('downloadSVG').addEventListener('click', downloadSVG);
414
+
415
+ // Copy button
416
+ document.getElementById('copyPath').addEventListener('click', copyPathData);
417
+
418
+ // Zoom control
419
+ zoomLevel.addEventListener('change', function() {
420
+ const scale = parseFloat(this.value);
421
+ svgCanvas.style.transform = `scale(${scale})`;
422
+ svgCanvas.style.transformOrigin = '0 0';
423
+ });
424
+
425
+ // Canvas click handler
426
+ svgCanvas.addEventListener('click', function(e) {
427
+ const rect = svgCanvas.getBoundingClientRect();
428
+ const x = e.clientX - rect.left;
429
+ const y = e.clientY - rect.top;
430
+
431
+ if (currentTool === 'pen') {
432
+ addPathPoint(x, y);
433
+ } else if (currentTool === 'select') {
434
+ selectPoint(x, y);
435
+ } else if (currentTool === 'delete') {
436
+ deletePoint(x, y);
437
+ }
438
+ });
439
+
440
+ // Canvas mousemove handler for dragging
441
+ svgCanvas.addEventListener('mousemove', function(e) {
442
+ if (activePoint && currentTool === 'select') {
443
+ const rect = svgCanvas.getBoundingClientRect();
444
+ const x = e.clientX - rect.left;
445
+ const y = e.clientY - rect.top;
446
+
447
+ // Update point position
448
+ activePoint.element.style.left = `${x}px`;
449
+ activePoint.element.style.top = `${y}px`;
450
+
451
+ // Update control points if they exist
452
+ if (activePoint.control1) {
453
+ const cx1 = x + (activePoint.control1.x - activePoint.x);
454
+ const cy1 = y + (activePoint.control1.y - activePoint.y);
455
+ activePoint.control1.element.style.left = `${cx1}px`;
456
+ activePoint.control1.element.style.top = `${cy1}px`;
457
+ activePoint.control1.x = cx1;
458
+ activePoint.control1.y = cy1;
459
+
460
+ // Update control line
461
+ const line1 = document.getElementById(`line-${activePoint.id}-1`);
462
+ if (line1) {
463
+ updateControlLine(line1, x, y, cx1, cy1);
464
+ }
465
+ }
466
+
467
+ if (activePoint.control2) {
468
+ const cx2 = x + (activePoint.control2.x - activePoint.x);
469
+ const cy2 = y + (activePoint.control2.y - activePoint.y);
470
+ activePoint.control2.element.style.left = `${cx2}px`;
471
+ activePoint.control2.element.style.top = `${cy2}px`;
472
+ activePoint.control2.x = cx2;
473
+ activePoint.control2.y = cy2;
474
+
475
+ // Update control line
476
+ const line2 = document.getElementById(`line-${activePoint.id}-2`);
477
+ if (line2) {
478
+ updateControlLine(line2, x, y, cx2, cy2);
479
+ }
480
+ }
481
+
482
+ // Update point coordinates
483
+ activePoint.x = x;
484
+ activePoint.y = y;
485
+
486
+ // Update properties panel
487
+ updatePropertiesPanel();
488
+
489
+ // Update path data
490
+ updatePathData();
491
+ }
492
+ });
493
+
494
+ svgCanvas.addEventListener('mouseup', function() {
495
+ activePoint = null;
496
+ });
497
+
498
+ function resetPath() {
499
+ // Clear existing elements
500
+ currentPoints.forEach(point => {
501
+ if (point.element && point.element.parentNode) {
502
+ point.element.parentNode.removeChild(point.element);
503
+ }
504
+ if (point.control1 && point.control1.element) {
505
+ point.control1.element.parentNode.removeChild(point.control1.element);
506
+ }
507
+ if (point.control2 && point.control2.element) {
508
+ point.control2.element.parentNode.removeChild(point.control2.element);
509
+ }
510
+ });
511
+
512
+ currentControlLines.forEach(line => {
513
+ if (line.parentNode) {
514
+ line.parentNode.removeChild(line);
515
+ }
516
+ });
517
+
518
+ // Reset arrays
519
+ currentPoints = [];
520
+ currentControlPoints = [];
521
+ currentControlLines = [];
522
+
523
+ // Create new path
524
+ if (currentPath && currentPath.parentNode) {
525
+ currentPath.parentNode.removeChild(currentPath);
526
+ }
527
+
528
+ currentPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
529
+ currentPath.setAttribute('fill', document.getElementById('fillColor').value);
530
+ currentPath.setAttribute('stroke', document.getElementById('strokeColor').value);
531
+ currentPath.setAttribute('stroke-width', document.getElementById('strokeWidth').value);
532
+ currentPath.setAttribute('d', '');
533
+ svgCanvas.appendChild(currentPath);
534
+
535
+ // Update path data
536
+ pathData.value = '';
537
+
538
+ // Hide properties panel
539
+ document.getElementById('propertiesPanel').classList.add('hidden');
540
+ }
541
+
542
+ function addPathPoint(x, y) {
543
+ const pointId = Date.now();
544
+
545
+ // Create point element
546
+ const pointElement = document.createElement('div');
547
+ pointElement.className = 'path-point';
548
+ pointElement.style.left = `${x}px`;
549
+ pointElement.style.top = `${y}px`;
550
+ pointElement.dataset.id = pointId;
551
+ svgContainer.appendChild(pointElement);
552
+
553
+ // Add event listeners for point selection
554
+ pointElement.addEventListener('mousedown', function(e) {
555
+ if (currentTool === 'select') {
556
+ e.stopPropagation();
557
+ activePoint = currentPoints.find(p => p.id === pointId);
558
+ selectPoint(x, y);
559
+ }
560
+ });
561
+
562
+ // Double click to change command type
563
+ pointElement.addEventListener('dblclick', function(e) {
564
+ e.stopPropagation();
565
+ const point = currentPoints.find(p => p.id === pointId);
566
+ if (point) {
567
+ const newCommand = prompt("Enter new command (M, L, H, V, C, Q, Z):", point.command);
568
+ if (newCommand && ['M', 'L', 'H', 'V', 'C', 'Q', 'Z'].includes(newCommand.toUpperCase())) {
569
+ point.command = newCommand.toUpperCase();
570
+
571
+ // Remove existing control points if changing from curve to non-curve
572
+ if ((point.command !== 'C' && point.command !== 'Q') && (point.control1 || point.control2)) {
573
+ if (point.control1) {
574
+ if (point.control1.element.parentNode) {
575
+ point.control1.element.parentNode.removeChild(point.control1.element);
576
+ }
577
+ const cp1Index = currentControlPoints.findIndex(cp => cp.id === point.control1.id);
578
+ if (cp1Index !== -1) {
579
+ currentControlPoints.splice(cp1Index, 1);
580
+ }
581
+ point.control1 = null;
582
+ }
583
+
584
+ if (point.control2) {
585
+ if (point.control2.element.parentNode) {
586
+ point.control2.element.parentNode.removeChild(point.control2.element);
587
+ }
588
+ const cp2Index = currentControlPoints.findIndex(cp => cp.id === point.control2.id);
589
+ if (cp2Index !== -1) {
590
+ currentControlPoints.splice(cp2Index, 1);
591
+ }
592
+ point.control2 = null;
593
+ }
594
+
595
+ // Remove control lines
596
+ const line1 = document.getElementById(`line-${point.id}-1`);
597
+ if (line1 && line1.parentNode) {
598
+ line1.parentNode.removeChild(line1);
599
+ }
600
+
601
+ const line2 = document.getElementById(`line-${point.id}-2`);
602
+ if (line2 && line2.parentNode) {
603
+ line2.parentNode.removeChild(line2);
604
+ }
605
+ }
606
+
607
+ // Add control points if changing to curve
608
+ if ((point.command === 'C' || point.command === 'Q') && !point.control1) {
609
+ addControlPoints(point);
610
+ }
611
+
612
+ updatePathData();
613
+ }
614
+ }
615
+ });
616
+
617
+ // Create point object
618
+ const point = {
619
+ id: pointId,
620
+ x: x,
621
+ y: y,
622
+ element: pointElement,
623
+ command: activeCommand
624
+ };
625
+
626
+ // For curve commands, add control points
627
+ if (activeCommand === 'C' || activeCommand === 'Q') {
628
+ addControlPoints(point);
629
+ }
630
+
631
+ currentPoints.push(point);
632
+ updatePathData();
633
+
634
+ // Select the newly created point
635
+ selectPoint(x, y);
636
+ }
637
+
638
+ function addControlPoints(point) {
639
+ // Control point 1
640
+ const control1Id = `${point.id}-1`;
641
+ const control1Element = document.createElement('div');
642
+ control1Element.className = 'control-point';
643
+ control1Element.style.left = `${point.x - 30}px`;
644
+ control1Element.style.top = `${point.y - 30}px`;
645
+ control1Element.dataset.id = control1Id;
646
+ svgContainer.appendChild(control1Element);
647
+
648
+ const control1 = {
649
+ id: control1Id,
650
+ x: point.x - 30,
651
+ y: point.y - 30,
652
+ element: control1Element,
653
+ parentPoint: point.id
654
+ };
655
+
656
+ // Control point 2 (for cubic curves)
657
+ let control2 = null;
658
+ if (point.command === 'C') {
659
+ const control2Id = `${point.id}-2`;
660
+ const control2Element = document.createElement('div');
661
+ control2Element.className = 'control-point';
662
+ control2Element.style.left = `${point.x + 30}px`;
663
+ control2Element.style.top = `${point.y + 30}px`;
664
+ control2Element.dataset.id = control2Id;
665
+ svgContainer.appendChild(control2Element);
666
+
667
+ control2 = {
668
+ id: control2Id,
669
+ x: point.x + 30,
670
+ y: point.y + 30,
671
+ element: control2Element,
672
+ parentPoint: point.id
673
+ };
674
+
675
+ currentControlPoints.push(control2);
676
+
677
+ // Add event listener for control point 2
678
+ control2Element.addEventListener('mousedown', function(e) {
679
+ if (currentTool === 'select') {
680
+ e.stopPropagation();
681
+ activePoint = control2;
682
+
683
+ // Create control line if it doesn't exist
684
+ const lineId = `line-${point.id}-2`;
685
+ let line = document.getElementById(lineId);
686
+ if (!line) {
687
+ line = createControlLine(point.x, point.y, control2.x, control2.y, lineId);
688
+ currentControlLines.push(line);
689
+ }
690
+ }
691
+ });
692
+ }
693
+
694
+ currentControlPoints.push(control1);
695
+ point.control1 = control1;
696
+ point.control2 = control2;
697
+
698
+ // Add event listener for control point 1
699
+ control1Element.addEventListener('mousedown', function(e) {
700
+ if (currentTool === 'select') {
701
+ e.stopPropagation();
702
+ activePoint = control1;
703
+
704
+ // Create control line if it doesn't exist
705
+ const lineId = `line-${point.id}-1`;
706
+ let line = document.getElementById(lineId);
707
+ if (!line) {
708
+ line = createControlLine(point.x, point.y, control1.x, control1.y, lineId);
709
+ currentControlLines.push(line);
710
+ }
711
+ }
712
+ });
713
+
714
+ // Create control lines
715
+ const line1 = createControlLine(point.x, point.y, control1.x, control1.y, `line-${point.id}-1`);
716
+ currentControlLines.push(line1);
717
+
718
+ if (control2) {
719
+ const line2 = createControlLine(point.x, point.y, control2.x, control2.y, `line-${point.id}-2`);
720
+ currentControlLines.push(line2);
721
+ }
722
+ }
723
+
724
+ function createControlLine(x1, y1, x2, y2, id) {
725
+ const line = document.createElement('div');
726
+ line.className = 'control-line';
727
+ line.id = id;
728
+
729
+ const dx = x2 - x1;
730
+ const dy = y2 - y1;
731
+ const length = Math.sqrt(dx * dx + dy * dy);
732
+ const angle = Math.atan2(dy, dx) * 180 / Math.PI;
733
+
734
+ line.style.width = `${length}px`;
735
+ line.style.left = `${x1}px`;
736
+ line.style.top = `${y1}px`;
737
+ line.style.transform = `rotate(${angle}deg)`;
738
+
739
+ svgContainer.appendChild(line);
740
+ return line;
741
+ }
742
+
743
+ function updateControlLine(line, x1, y1, x2, y2) {
744
+ const dx = x2 - x1;
745
+ const dy = y2 - y1;
746
+ const length = Math.sqrt(dx * dx + dy * dy);
747
+ const angle = Math.atan2(dy, dx) * 180 / Math.PI;
748
+
749
+ line.style.width = `${length}px`;
750
+ line.style.left = `${x1}px`;
751
+ line.style.top = `${y1}px`;
752
+ line.style.transform = `rotate(${angle}deg)`;
753
+ }
754
+
755
+ function selectPoint(x, y) {
756
+ // Find the closest point
757
+ let closestPoint = null;
758
+ let minDistance = Infinity;
759
+
760
+ currentPoints.forEach(point => {
761
+ const distance = Math.sqrt(Math.pow(point.x - x, 2) + Math.pow(point.y - y, 2));
762
+ if (distance < minDistance && distance < 20) { // 20px threshold
763
+ minDistance = distance;
764
+ closestPoint = point;
765
+ }
766
+ });
767
+
768
+ // Also check control points
769
+ currentControlPoints.forEach(point => {
770
+ const distance = Math.sqrt(Math.pow(point.x - x, 2) + Math.pow(point.y - y, 2));
771
+ if (distance < minDistance && distance < 20) { // 20px threshold
772
+ minDistance = distance;
773
+ closestPoint = point;
774
+ }
775
+ });
776
+
777
+ // Update active point
778
+ if (closestPoint) {
779
+ // Remove active class from all points
780
+ document.querySelectorAll('.path-point').forEach(el => el.classList.remove('active'));
781
+
782
+ // Add active class to selected point
783
+ if (closestPoint.element) {
784
+ closestPoint.element.classList.add('active');
785
+ }
786
+
787
+ activePoint = closestPoint;
788
+ updatePropertiesPanel();
789
+ }
790
+ }
791
+
792
+ function deletePoint(x, y) {
793
+ // Find the closest point
794
+ let closestPoint = null;
795
+ let minDistance = Infinity;
796
+ let pointIndex = -1;
797
+
798
+ currentPoints.forEach((point, index) => {
799
+ const distance = Math.sqrt(Math.pow(point.x - x, 2) + Math.pow(point.y - y, 2));
800
+ if (distance < minDistance && distance < 20) { // 20px threshold
801
+ minDistance = distance;
802
+ closestPoint = point;
803
+ pointIndex = index;
804
+ }
805
+ });
806
+
807
+ // Also check control points
808
+ currentControlPoints.forEach((point, index) => {
809
+ const distance = Math.sqrt(Math.pow(point.x - x, 2) + Math.pow(point.y - y, 2));
810
+ if (distance < minDistance && distance < 20) { // 20px threshold
811
+ minDistance = distance;
812
+ closestPoint = point;
813
+ pointIndex = index;
814
+ }
815
+ });
816
+
817
+ if (closestPoint) {
818
+ // Remove point element from DOM
819
+ if (closestPoint.element && closestPoint.element.parentNode) {
820
+ closestPoint.element.parentNode.removeChild(closestPoint.element);
821
+ }
822
+
823
+ // Remove from appropriate array
824
+ if (currentPoints.includes(closestPoint)) {
825
+ currentPoints.splice(pointIndex, 1);
826
+
827
+ // Also remove associated control points
828
+ if (closestPoint.control1) {
829
+ const cp1Index = currentControlPoints.findIndex(cp => cp.id === closestPoint.control1.id);
830
+ if (cp1Index !== -1) {
831
+ if (currentControlPoints[cp1Index].element.parentNode) {
832
+ currentControlPoints[cp1Index].element.parentNode.removeChild(currentControlPoints[cp1Index].element);
833
+ }
834
+ currentControlPoints.splice(cp1Index, 1);
835
+ }
836
+ }
837
+
838
+ if (closestPoint.control2) {
839
+ const cp2Index = currentControlPoints.findIndex(cp => cp.id === closestPoint.control2.id);
840
+ if (cp2Index !== -1) {
841
+ if (currentControlPoints[cp2Index].element.parentNode) {
842
+ currentControlPoints[cp2Index].element.parentNode.removeChild(currentControlPoints[cp2Index].element);
843
+ }
844
+ currentControlPoints.splice(cp2Index, 1);
845
+ }
846
+ }
847
+
848
+ // Remove control lines
849
+ const line1 = document.getElementById(`line-${closestPoint.id}-1`);
850
+ if (line1 && line1.parentNode) {
851
+ line1.parentNode.removeChild(line1);
852
+ }
853
+
854
+ const line2 = document.getElementById(`line-${closestPoint.id}-2`);
855
+ if (line2 && line2.parentNode) {
856
+ line2.parentNode.removeChild(line2);
857
+ }
858
+ } else if (currentControlPoints.includes(closestPoint)) {
859
+ currentControlPoints.splice(pointIndex, 1);
860
+ }
861
+
862
+ updatePathData();
863
+ }
864
+ }
865
+
866
+ function updatePathData() {
867
+ if (currentPoints.length === 0) {
868
+ currentPath.setAttribute('d', '');
869
+ pathData.value = '';
870
+ return;
871
+ }
872
+
873
+ let d = '';
874
+
875
+ currentPoints.forEach((point, index) => {
876
+ if (index === 0) {
877
+ d += `${point.command} ${point.x},${point.y} `;
878
+ } else {
879
+ switch (point.command) {
880
+ case 'L':
881
+ d += `L ${point.x},${point.y} `;
882
+ break;
883
+ case 'H':
884
+ d += `H ${point.x} `;
885
+ break;
886
+ case 'V':
887
+ d += `V ${point.y} `;
888
+ break;
889
+ case 'C':
890
+ if (point.control1 && point.control2) {
891
+ d += `C ${point.control1.x},${point.control1.y} ${point.control2.x},${point.control2.y} ${point.x},${point.y} `;
892
+ }
893
+ break;
894
+ case 'Q':
895
+ if (point.control1) {
896
+ d += `Q ${point.control1.x},${point.control1.y} ${point.x},${point.y} `;
897
+ }
898
+ break;
899
+ case 'Z':
900
+ d += 'Z ';
901
+ break;
902
+ default:
903
+ d += `L ${point.x},${point.y} `;
904
+ }
905
+ }
906
+ });
907
+
908
+ currentPath.setAttribute('d', d.trim());
909
+ pathData.value = d.trim();
910
+ }
911
+
912
+ function updatePathStyle() {
913
+ currentPath.setAttribute('stroke', document.getElementById('strokeColor').value);
914
+ currentPath.setAttribute('stroke-width', document.getElementById('strokeWidth').value);
915
+ currentPath.setAttribute('fill', document.getElementById('fillColor').value);
916
+ }
917
+
918
+ function updatePropertiesPanel() {
919
+ if (!activePoint) {
920
+ document.getElementById('propertiesPanel').classList.add('hidden');
921
+ return;
922
+ }
923
+
924
+ document.getElementById('propertiesPanel').classList.remove('hidden');
925
+ document.getElementById('pointX').value = Math.round(activePoint.x);
926
+ document.getElementById('pointY').value = Math.round(activePoint.y);
927
+
928
+ // Update event listeners for property changes
929
+ document.getElementById('pointX').oninput = function() {
930
+ activePoint.x = parseFloat(this.value);
931
+ activePoint.element.style.left = `${activePoint.x}px`;
932
+
933
+ if (activePoint.control1) {
934
+ const dx = activePoint.control1.x - activePoint.x;
935
+ activePoint.control1.x = parseFloat(this.value) + dx;
936
+ activePoint.control1.element.style.left = `${activePoint.control1.x}px`;
937
+
938
+ const line1 = document.getElementById(`line-${activePoint.id}-1`);
939
+ if (line1) {
940
+ updateControlLine(line1, activePoint.x, activePoint.y, activePoint.control1.x, activePoint.control1.y);
941
+ }
942
+ }
943
+
944
+ if (activePoint.control2) {
945
+ const dx = activePoint.control2.x - activePoint.x;
946
+ activePoint.control2.x = parseFloat(this.value) + dx;
947
+ activePoint.control2.element.style.left = `${activePoint.control2.x}px`;
948
+
949
+ const line2 = document.getElementById(`line-${activePoint.id}-2`);
950
+ if (line2) {
951
+ updateControlLine(line2, activePoint.x, activePoint.y, activePoint.control2.x, activePoint.control2.y);
952
+ }
953
+ }
954
+
955
+ updatePathData();
956
+ };
957
+
958
+ document.getElementById('pointY').oninput = function() {
959
+ activePoint.y = parseFloat(this.value);
960
+ activePoint.element.style.top = `${activePoint.y}px`;
961
+
962
+ if (activePoint.control1) {
963
+ const dy = activePoint.control1.y - activePoint.y;
964
+ activePoint.control1.y = parseFloat(this.value) + dy;
965
+ activePoint.control1.element.style.top = `${activePoint.control1.y}px`;
966
+
967
+ const line1 = document.getElementById(`line-${activePoint.id}-1`);
968
+ if (line1) {
969
+ updateControlLine(line1, activePoint.x, activePoint.y, activePoint.control1.x, activePoint.control1.y);
970
+ }
971
+ }
972
+
973
+ if (activePoint.control2) {
974
+ const dy = activePoint.control2.y - activePoint.y;
975
+ activePoint.control2.y = parseFloat(this.value) + dy;
976
+ activePoint.control2.element.style.top = `${activePoint.control2.y}px`;
977
+
978
+ const line2 = document.getElementById(`line-${activePoint.id}-2`);
979
+ if (line2) {
980
+ updateControlLine(line2, activePoint.x, activePoint.y, activePoint.control2.x, activePoint.control2.y);
981
+ }
982
+ }
983
+
984
+ updatePathData();
985
+ };
986
+ }
987
+
988
+ function downloadSVG() {
989
+ const svgData = `
990
+ <svg xmlns="http://www.w3.org/2000/svg" width="600" height="400" viewBox="0 0 600 400">
991
+ ${currentPath.outerHTML}
992
+ </svg>
993
+ `;
994
+
995
+ const blob = new Blob([svgData], {type: 'image/svg+xml'});
996
+ const url = URL.createObjectURL(blob);
997
+
998
+ const a = document.createElement('a');
999
+ a.href = url;
1000
+ a.download = 'svg-path.svg';
1001
+ document.body.appendChild(a);
1002
+ a.click();
1003
+ document.body.removeChild(a);
1004
+ URL.revokeObjectURL(url);
1005
+ }
1006
+
1007
+ function copyPathData() {
1008
+ pathData.select();
1009
+ document.execCommand('copy');
1010
+
1011
+ // Show feedback
1012
+ const copyBtn = document.getElementById('copyPath');
1013
+ const originalText = copyBtn.innerHTML;
1014
+ copyBtn.innerHTML = '<i class="fas fa-check mr-1"></i> Copied!';
1015
+
1016
+ setTimeout(() => {
1017
+ copyBtn.innerHTML = originalText;
1018
+ }, 2000);
1019
+ }
1020
+ });
1021
+ </script>
1022
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=MarkTheArtist/svg-creator" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1023
+ </html>