Compare commits

11 Commits
cli ... master

Author SHA1 Message Date
54f6183eb3 Merge branch 'migrate-svg-nametag-format' into web-app, but for real
this time
2026-07-25 16:35:17 -04:00
e3040e3ee0 committing uncommited work 2026-07-25 16:34:35 -04:00
58119d79f4 Merge branch 'migrate-svg-nametag-format' into web-app 2026-07-25 16:33:07 -04:00
5421d38397 Add link to git tea source page in corner 2026-04-11 13:19:47 -04:00
1619ec9701 Add text inset for better adhesion
- Increase text thickness to 2.3mm (base 2.0mm + 0.3mm inset compensation)
- Adjust text Z offset to 2.7mm to inset text into background
- Add offset() call for text layers to create interference fit
- Total height remains at 5mm
2026-04-11 13:07:43 -04:00
unfunny
4521e9cc18 Fix this link 2026-02-14 20:05:19 -05:00
000d976198 update readme 2026-02-14 20:02:15 -05:00
unfunny
bfc9ab3bca Upload files to "/" 2026-02-14 19:58:46 -05:00
11f0464cee add readme (thx gemini) 2026-02-14 19:47:18 -05:00
48aa59540a feat: implement pwa, add dockerfiles for web and cli, and introduce folder selection with wasm error handling. 2026-02-14 19:44:19 -05:00
91e7af0c04 chore: add webapp node_modules dependencies. 2026-02-14 17:28:26 -05:00
29 changed files with 13834 additions and 19 deletions

4
.gitignore vendored
View File

@@ -1,3 +1,5 @@
.venv/
nametags/
stls/
stls/
SVGs/
nametags.zip

16
Dockerfile.cli Normal file
View File

@@ -0,0 +1,16 @@
FROM python:3.11-slim
# Install system dependencies for trimesh/shapely if needed
RUN apt-get update && apt-get install -y \
libgl1-mesa-glx \
libglib2.0-0 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY convert_nametags.py .
ENTRYPOINT ["python", "convert_nametags.py"]

View File

@@ -20,5 +20,5 @@ The program automatically scales all designs to these specific measurements for
- **Total Height**: 5.0 mm
## Ways to Use
- **Web App**: The easiest way! Just open the web page, drag your files in, and download the results. No installation required.
- **Python Tool**: For advanced users who want to process hundreds of files at once using the command line. Requires Python 3.12 or higher and some basic knowledge of the command line.
- **Web App**: The easiest way! Just open the web page, drag your files in, and download the results. No installation required. Note: The Web App currently does not support New Format SVGs. It can only read a direct export from Adobe Illustrator.
- **Python Tool**: For advanced users who want to process hundreds of files at once using the command line. Requires Python 3.12 or higher and some basic knowledge of the command line. Supports New Format.

868
analysis_output.txt Normal file
View File

@@ -0,0 +1,868 @@
######################################################################
# OLD FORMAT FILES (nametags/)
######################################################################
======================================================================
[OLD] Staff Nametags rex.svg
======================================================================
viewBox: 0 0 221.23 72
xmlns: http://www.w3.org/2000/svg
version: 1.1
<style> blocks: 1
<g> groups: 15
--- BACKGROUND (1 path elements) ---
path[0]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=55, class='', fill=''
--- WHITE (3 path elements) ---
path[0]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=232, class='st2', fill=''
path[1]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=83, class='st2', fill=''
path[2]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=118, class='st2', fill=''
--- CYAN (25 path elements) ---
path[0]: 65 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=895, class='st1', fill=''
path[1]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=243, class='st1', fill=''
path[2]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=224, class='st1', fill=''
path[3]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=224, class='st1', fill=''
path[4]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=100, class='st1', fill=''
path[5]: 20 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=251, class='st1', fill=''
path[6]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=68, class='st1', fill=''
path[7]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=146, class='st1', fill=''
path[8]: 25 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=355, class='st1', fill=''
path[9]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=156, class='st1', fill=''
path[10]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=226, class='st1', fill=''
path[11]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=101, class='st1', fill=''
path[12]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=226, class='st1', fill=''
path[13]: 19 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=183, class='st1', fill=''
path[14]: 12 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=68, class='st1', fill=''
path[15]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=144, class='st1', fill=''
path[16]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=147, class='st1', fill=''
path[17]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=259, class='st1', fill=''
path[18]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=44, class='st1', fill=''
path[19]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=224, class='st1', fill=''
path[20]: 15 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=118, class='st1', fill=''
path[21]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=99, class='st1', fill=''
path[22]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=67, class='st1', fill=''
path[23]: 20 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=251, class='st1', fill=''
path[24]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=325, class='st1', fill=''
======================================================================
[OLD] Staff Nametags001000.svg
======================================================================
viewBox: 0 0 221.23 72
xmlns: http://www.w3.org/2000/svg
version: 1.1
<style> blocks: 1
<g> groups: 8
--- BACKGROUND (1 path elements) ---
path[0]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=55, class='', fill=''
--- WHITE (9 path elements) ---
path[0]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=119, class='st2', fill=''
path[1]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=45, class='st2', fill=''
path[2]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=119, class='st2', fill=''
path[3]: 12 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=79, class='st2', fill=''
path[4]: 12 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=234, class='st2', fill=''
path[5]: 24 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=373, class='st2', fill=''
path[6]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=155, class='st2', fill=''
path[7]: 17 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=242, class='st2', fill=''
path[8]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=165, class='st2', fill=''
--- CYAN (37 path elements) ---
path[0]: 65 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=895, class='st1', fill=''
path[1]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=329, class='st1', fill=''
path[2]: 17 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=257, class='st1', fill=''
path[3]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=229, class='st1', fill=''
path[4]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=143, class='st1', fill=''
path[5]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=100, class='st1', fill=''
path[6]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=68, class='st1', fill=''
path[7]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=155, class='st1', fill=''
path[8]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=160, class='st1', fill=''
path[9]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=245, class='st1', fill=''
path[10]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=226, class='st1', fill=''
path[11]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=226, class='st1', fill=''
path[12]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=101, class='st1', fill=''
path[13]: 20 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=253, class='st1', fill=''
path[14]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=70, class='st1', fill=''
path[15]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=147, class='st1', fill=''
path[16]: 25 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=356, class='st1', fill=''
path[17]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=156, class='st1', fill=''
path[18]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=226, class='st1', fill=''
path[19]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=101, class='st1', fill=''
path[20]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=219, class='st1', fill=''
path[21]: 17 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=258, class='st1', fill=''
path[22]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=146, class='st1', fill=''
path[23]: 25 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=355, class='st1', fill=''
path[24]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=68, class='st1', fill=''
path[25]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=324, class='st1', fill=''
path[26]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=319, class='st1', fill=''
path[27]: 25 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=355, class='st1', fill=''
path[28]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=147, class='st1', fill=''
path[29]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=229, class='st1', fill=''
path[30]: 17 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=259, class='st1', fill=''
path[31]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=245, class='st1', fill=''
path[32]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=147, class='st1', fill=''
path[33]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=144, class='st1', fill=''
path[34]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=101, class='st1', fill=''
path[35]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=230, class='st1', fill=''
path[36]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=147, class='st1', fill=''
======================================================================
[OLD] Staff Nametags002000.svg
======================================================================
viewBox: 0 0 221.23 72
xmlns: http://www.w3.org/2000/svg
version: 1.1
<style> blocks: 1
<g> groups: 8
--- BACKGROUND (1 path elements) ---
path[0]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=55, class='', fill=''
--- WHITE (8 path elements) ---
path[0]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=119, class='st2', fill=''
path[1]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=45, class='st2', fill=''
path[2]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=119, class='st2', fill=''
path[3]: 12 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=79, class='st2', fill=''
path[4]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=121, class='st2', fill=''
path[5]: 19 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=196, class='st2', fill=''
path[6]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close'}, d-len=194, class='st2', fill=''
path[7]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=164, class='st2', fill=''
--- CYAN (34 path elements) ---
path[0]: 65 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=895, class='st1', fill=''
path[1]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=329, class='st1', fill=''
path[2]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=224, class='st1', fill=''
path[3]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=229, class='st1', fill=''
path[4]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=68, class='st1', fill=''
path[5]: 25 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=354, class='st1', fill=''
path[6]: 6 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=35, class='st1', fill=''
path[7]: 15 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=100, class='st1', fill=''
path[8]: 17 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=257, class='st1', fill=''
path[9]: 20 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=253, class='st1', fill=''
path[10]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=70, class='st1', fill=''
path[11]: 25 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=356, class='st1', fill=''
path[12]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=245, class='st1', fill=''
path[13]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=223, class='st1', fill=''
path[14]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=225, class='st1', fill=''
path[15]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=101, class='st1', fill=''
path[16]: 20 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=253, class='st1', fill=''
path[17]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=70, class='st1', fill=''
path[18]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=147, class='st1', fill=''
path[19]: 25 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=355, class='st1', fill=''
path[20]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=156, class='st1', fill=''
path[21]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=226, class='st1', fill=''
path[22]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=101, class='st1', fill=''
path[23]: 12 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=133, class='st1', fill=''
path[24]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=146, class='st1', fill=''
path[25]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=68, class='st1', fill=''
path[26]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=223, class='st1', fill=''
path[27]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=146, class='st1', fill=''
path[28]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=329, class='st1', fill=''
path[29]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=225, class='st1', fill=''
path[30]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=230, class='st1', fill=''
path[31]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=70, class='st1', fill=''
path[32]: 25 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=357, class='st1', fill=''
path[33]: 6 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=36, class='st1', fill=''
======================================================================
[OLD] Staff Nametags011000.svg
======================================================================
viewBox: 0 0 221.23 72
xmlns: http://www.w3.org/2000/svg
version: 1.1
<style> blocks: 1
<g> groups: 8
--- BACKGROUND (1 path elements) ---
path[0]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=55, class='', fill=''
--- WHITE (12 path elements) ---
path[0]: 28 segments, 3 loops, 3 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=328, class='st2', fill=''
path[1]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=227, class='st2', fill=''
path[2]: 6 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=36, class='st2', fill=''
path[3]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=56, class='st2', fill=''
path[4]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=58, class='st2', fill=''
path[5]: 12 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=80, class='st2', fill=''
path[6]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=78, class='st2', fill=''
path[7]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=82, class='st2', fill=''
path[8]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=74, class='st2', fill=''
path[9]: 24 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=374, class='st2', fill=''
path[10]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=345, class='st2', fill=''
path[11]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=169, class='st2', fill=''
--- CYAN (37 path elements) ---
path[0]: 65 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=895, class='st1', fill=''
path[1]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=58, class='st1', fill=''
path[2]: 17 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=257, class='st1', fill=''
path[3]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=229, class='st1', fill=''
path[4]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=146, class='st1', fill=''
path[5]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=58, class='st1', fill=''
path[6]: 17 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=257, class='st1', fill=''
path[7]: 25 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=354, class='st1', fill=''
path[8]: 21 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=246, class='st1', fill=''
path[9]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=245, class='st1', fill=''
path[10]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=226, class='st1', fill=''
path[11]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=226, class='st1', fill=''
path[12]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=101, class='st1', fill=''
path[13]: 20 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=252, class='st1', fill=''
path[14]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=70, class='st1', fill=''
path[15]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=147, class='st1', fill=''
path[16]: 25 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=356, class='st1', fill=''
path[17]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=156, class='st1', fill=''
path[18]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=226, class='st1', fill=''
path[19]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=101, class='st1', fill=''
path[20]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=219, class='st1', fill=''
path[21]: 17 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=258, class='st1', fill=''
path[22]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=146, class='st1', fill=''
path[23]: 25 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=355, class='st1', fill=''
path[24]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=68, class='st1', fill=''
path[25]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=324, class='st1', fill=''
path[26]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=319, class='st1', fill=''
path[27]: 25 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=355, class='st1', fill=''
path[28]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=147, class='st1', fill=''
path[29]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=229, class='st1', fill=''
path[30]: 17 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=259, class='st1', fill=''
path[31]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=245, class='st1', fill=''
path[32]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=147, class='st1', fill=''
path[33]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=144, class='st1', fill=''
path[34]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=101, class='st1', fill=''
path[35]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=230, class='st1', fill=''
path[36]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=147, class='st1', fill=''
======================================================================
[OLD] Staff Nametags029000.svg
======================================================================
viewBox: 0 0 221.23 72
xmlns: http://www.w3.org/2000/svg
version: 1.1
<style> blocks: 1
<g> groups: 8
--- BACKGROUND (1 path elements) ---
path[0]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=55, class='', fill=''
--- WHITE (10 path elements) ---
path[0]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=101, class='st2', fill=''
path[1]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=119, class='st2', fill=''
path[2]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=57, class='st2', fill=''
path[3]: 6 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=36, class='st2', fill=''
path[4]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=77, class='st2', fill=''
path[5]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=120, class='st2', fill=''
path[6]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=152, class='st2', fill=''
path[7]: 21 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=341, class='st2', fill=''
path[8]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=281, class='st2', fill=''
path[9]: 6 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=38, class='st2', fill=''
--- CYAN (36 path elements) ---
path[0]: 65 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=895, class='st1', fill=''
path[1]: 12 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=66, class='st1', fill=''
path[2]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=67, class='st1', fill=''
path[3]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=100, class='st1', fill=''
path[4]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=324, class='st1', fill=''
path[5]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=155, class='st1', fill=''
path[6]: 6 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=35, class='st1', fill=''
path[7]: 21 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=245, class='st1', fill=''
path[8]: 20 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=252, class='st1', fill=''
path[9]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=101, class='st1', fill=''
path[10]: 17 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=259, class='st1', fill=''
path[11]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=325, class='st1', fill=''
path[12]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=325, class='st1', fill=''
path[13]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=70, class='st1', fill=''
path[14]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=226, class='st1', fill=''
path[15]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=147, class='st1', fill=''
path[16]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=320, class='st1', fill=''
path[17]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=245, class='st1', fill=''
path[18]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=226, class='st1', fill=''
path[19]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=226, class='st1', fill=''
path[20]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=101, class='st1', fill=''
path[21]: 20 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=252, class='st1', fill=''
path[22]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=67, class='st1', fill=''
path[23]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=147, class='st1', fill=''
path[24]: 25 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=356, class='st1', fill=''
path[25]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=156, class='st1', fill=''
path[26]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=226, class='st1', fill=''
path[27]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=101, class='st1', fill=''
path[28]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=259, class='st1', fill=''
path[29]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=44, class='st1', fill=''
path[30]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=224, class='st1', fill=''
path[31]: 15 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=117, class='st1', fill=''
path[32]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=99, class='st1', fill=''
path[33]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=68, class='st1', fill=''
path[34]: 20 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=251, class='st1', fill=''
path[35]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=325, class='st1', fill=''
======================================================================
[OLD] Staff NametagsRenny.svg
======================================================================
viewBox: 0 0 221.23 72
xmlns: http://www.w3.org/2000/svg
version: 1.1
<style> blocks: 1
<g> groups: 15
--- BACKGROUND (1 path elements) ---
path[0]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=55, class='', fill=''
--- WHITE (5 path elements) ---
path[0]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=232, class='st2', fill=''
path[1]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=83, class='st2', fill=''
path[2]: 12 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=83, class='st2', fill=''
path[3]: 12 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=82, class='st2', fill=''
path[4]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=87, class='st2', fill=''
--- CYAN (25 path elements) ---
path[0]: 65 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=895, class='st1', fill=''
path[1]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=243, class='st1', fill=''
path[2]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=224, class='st1', fill=''
path[3]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=224, class='st1', fill=''
path[4]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=100, class='st1', fill=''
path[5]: 20 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=251, class='st1', fill=''
path[6]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=68, class='st1', fill=''
path[7]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=146, class='st1', fill=''
path[8]: 25 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=355, class='st1', fill=''
path[9]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=156, class='st1', fill=''
path[10]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=226, class='st1', fill=''
path[11]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=101, class='st1', fill=''
path[12]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=226, class='st1', fill=''
path[13]: 19 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=183, class='st1', fill=''
path[14]: 12 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=68, class='st1', fill=''
path[15]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=144, class='st1', fill=''
path[16]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=147, class='st1', fill=''
path[17]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=259, class='st1', fill=''
path[18]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=44, class='st1', fill=''
path[19]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=224, class='st1', fill=''
path[20]: 15 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=118, class='st1', fill=''
path[21]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=99, class='st1', fill=''
path[22]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=67, class='st1', fill=''
path[23]: 20 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=251, class='st1', fill=''
path[24]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=325, class='st1', fill=''
######################################################################
# NEW FORMAT FILES (input/)
######################################################################
======================================================================
[NEW] CathyCanby_nametag.svg
======================================================================
viewBox: 0 0 221.23 72.0
xmlns: http://www.w3.org/2000/svg
version:
<style> blocks: 0
<g> groups: 0
--- BACKGROUND (1 path elements) ---
path[0]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=55, class='', fill='#000000'
--- WHITE (14 path elements) ---
path[0]: 19 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=399, class='', fill='#ffffff'
path[1]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=116, class='', fill='#ffffff'
path[2]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=139, class='', fill='#ffffff'
path[3]: 5 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=33, class='', fill='#ffffff'
path[4]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=609, class='', fill='#ffffff'
path[5]: 13 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=167, class='', fill='#ffffff'
path[6]: 9 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=85, class='', fill='#ffffff'
path[7]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=135, class='', fill='#ffffff'
path[8]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=129, class='', fill='#ffffff'
path[9]: 12 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=676, class='', fill='#ffffff'
path[10]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=916, class='', fill='#ffffff'
path[11]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=347, class='', fill='#ffffff'
path[12]: 17 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=715, class='', fill='#ffffff'
path[13]: 12 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=442, class='', fill='#ffffff'
--- CYAN (37 path elements) ---
path[0]: 65 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=895, class='', fill='#00aeef'
path[1]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=559, class='', fill='#00aeef'
path[2]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=602, class='', fill='#00aeef'
path[3]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=367, class='', fill='#00aeef'
path[4]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=345, class='', fill='#00aeef'
path[5]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=585, class='', fill='#00aeef'
path[6]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=633, class='', fill='#00aeef'
path[7]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=445, class='', fill='#00aeef'
path[8]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=128, class='', fill='#00aeef'
path[9]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=902, class='', fill='#00aeef'
path[10]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=473, class='', fill='#00aeef'
path[11]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1249, class='', fill='#00aeef'
path[12]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=519, class='', fill='#00aeef'
path[13]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=152, class='', fill='#00aeef'
path[14]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=313, class='', fill='#00aeef'
path[15]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=853, class='', fill='#00aeef'
path[16]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=712, class='', fill='#00aeef'
path[17]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=613, class='', fill='#00aeef'
path[18]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=749, class='', fill='#00aeef'
path[19]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=253, class='', fill='#00aeef'
path[20]: 19 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=380, class='', fill='#00aeef'
path[21]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=697, class='', fill='#00aeef'
path[22]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=366, class='', fill='#00aeef'
path[23]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=881, class='', fill='#00aeef'
path[24]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=118, class='', fill='#00aeef'
path[25]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1126, class='', fill='#00aeef'
path[26]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1210, class='', fill='#00aeef'
path[27]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1230, class='', fill='#00aeef'
path[28]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=473, class='', fill='#00aeef'
path[29]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=886, class='', fill='#00aeef'
path[30]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=945, class='', fill='#00aeef'
path[31]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=847, class='', fill='#00aeef'
path[32]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=451, class='', fill='#00aeef'
path[33]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=523, class='', fill='#00aeef'
path[34]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=334, class='', fill='#00aeef'
path[35]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=886, class='', fill='#00aeef'
path[36]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=461, class='', fill='#00aeef'
======================================================================
[NEW] JordanSmith_nametag.svg
======================================================================
viewBox: 0 0 221.23 72.0
xmlns: http://www.w3.org/2000/svg
version:
<style> blocks: 0
<g> groups: 0
--- BACKGROUND (1 path elements) ---
path[0]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=55, class='', fill='#000000'
--- WHITE (11 path elements) ---
path[0]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=288, class='', fill='#ffffff'
path[1]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=491, class='', fill='#ffffff'
path[2]: 19 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=387, class='', fill='#ffffff'
path[3]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=398, class='', fill='#ffffff'
path[4]: 13 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=258, class='', fill='#ffffff'
path[5]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=172, class='', fill='#ffffff'
path[6]: 16 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=916, class='', fill='#ffffff'
path[7]: 21 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=708, class='', fill='#ffffff'
path[8]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=140, class='', fill='#ffffff'
path[9]: 17 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=521, class='', fill='#ffffff'
path[10]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=377, class='', fill='#ffffff'
--- CYAN (40 path elements) ---
path[0]: 65 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=895, class='', fill='#00aeef'
path[1]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=119, class='', fill='#00aeef'
path[2]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=228, class='', fill='#00aeef'
path[3]: 19 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=733, class='', fill='#00aeef'
path[4]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=582, class='', fill='#00aeef'
path[5]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=232, class='', fill='#00aeef'
path[6]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=117, class='', fill='#00aeef'
path[7]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=832, class='', fill='#00aeef'
path[8]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=428, class='', fill='#00aeef'
path[9]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=825, class='', fill='#00aeef'
path[10]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=852, class='', fill='#00aeef'
path[11]: 9 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=112, class='', fill='#00aeef'
path[12]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=945, class='', fill='#00aeef'
path[13]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1186, class='', fill='#00aeef'
path[14]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=782, class='', fill='#00aeef'
path[15]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=519, class='', fill='#00aeef'
path[16]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=112, class='', fill='#00aeef'
path[17]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=251, class='', fill='#00aeef'
path[18]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=638, class='', fill='#00aeef'
path[19]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=662, class='', fill='#00aeef'
path[20]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=470, class='', fill='#00aeef'
path[21]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=759, class='', fill='#00aeef'
path[22]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=281, class='', fill='#00aeef'
path[23]: 19 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=380, class='', fill='#00aeef'
path[24]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=697, class='', fill='#00aeef'
path[25]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=366, class='', fill='#00aeef'
path[26]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=881, class='', fill='#00aeef'
path[27]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=118, class='', fill='#00aeef'
path[28]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1126, class='', fill='#00aeef'
path[29]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1210, class='', fill='#00aeef'
path[30]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1230, class='', fill='#00aeef'
path[31]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=473, class='', fill='#00aeef'
path[32]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=886, class='', fill='#00aeef'
path[33]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=945, class='', fill='#00aeef'
path[34]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=847, class='', fill='#00aeef'
path[35]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=451, class='', fill='#00aeef'
path[36]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=523, class='', fill='#00aeef'
path[37]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=334, class='', fill='#00aeef'
path[38]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=886, class='', fill='#00aeef'
path[39]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=461, class='', fill='#00aeef'
======================================================================
[NEW] JoshWyles_nametag.svg
======================================================================
viewBox: 0 0 221.23 72.0
xmlns: http://www.w3.org/2000/svg
version:
<style> blocks: 0
<g> groups: 0
--- BACKGROUND (1 path elements) ---
path[0]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=55, class='', fill='#000000'
--- WHITE (13 path elements) ---
path[0]: 19 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=399, class='', fill='#ffffff'
path[1]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=116, class='', fill='#ffffff'
path[2]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=139, class='', fill='#ffffff'
path[3]: 5 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=33, class='', fill='#ffffff'
path[4]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=352, class='', fill='#ffffff'
path[5]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=551, class='', fill='#ffffff'
path[6]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=818, class='', fill='#ffffff'
path[7]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=133, class='', fill='#ffffff'
path[8]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=252, class='', fill='#ffffff'
path[9]: 12 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=484, class='', fill='#ffffff'
path[10]: 5 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=55, class='', fill='#ffffff'
path[11]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=705, class='', fill='#ffffff'
path[12]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1147, class='', fill='#ffffff'
--- CYAN (37 path elements) ---
path[0]: 65 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=895, class='', fill='#00aeef'
path[1]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=97, class='', fill='#00aeef'
path[2]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=733, class='', fill='#00aeef'
path[3]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=466, class='', fill='#00aeef'
path[4]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=393, class='', fill='#00aeef'
path[5]: 23 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=983, class='', fill='#00aeef'
path[6]: 13 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=173, class='', fill='#00aeef'
path[7]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=689, class='', fill='#00aeef'
path[8]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=371, class='', fill='#00aeef'
path[9]: 5 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=36, class='', fill='#00aeef'
path[10]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=488, class='', fill='#00aeef'
path[11]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1105, class='', fill='#00aeef'
path[12]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=383, class='', fill='#00aeef'
path[13]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=142, class='', fill='#00aeef'
path[14]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=283, class='', fill='#00aeef'
path[15]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=793, class='', fill='#00aeef'
path[16]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=628, class='', fill='#00aeef'
path[17]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=551, class='', fill='#00aeef'
path[18]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=638, class='', fill='#00aeef'
path[19]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=253, class='', fill='#00aeef'
path[20]: 19 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=380, class='', fill='#00aeef'
path[21]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=697, class='', fill='#00aeef'
path[22]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=366, class='', fill='#00aeef'
path[23]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=881, class='', fill='#00aeef'
path[24]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=118, class='', fill='#00aeef'
path[25]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1126, class='', fill='#00aeef'
path[26]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1210, class='', fill='#00aeef'
path[27]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1230, class='', fill='#00aeef'
path[28]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=473, class='', fill='#00aeef'
path[29]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=886, class='', fill='#00aeef'
path[30]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=945, class='', fill='#00aeef'
path[31]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=847, class='', fill='#00aeef'
path[32]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=451, class='', fill='#00aeef'
path[33]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=523, class='', fill='#00aeef'
path[34]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=334, class='', fill='#00aeef'
path[35]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=886, class='', fill='#00aeef'
path[36]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=461, class='', fill='#00aeef'
======================================================================
[NEW] JoshWyles_nametag_1.svg
======================================================================
viewBox: 0 0 221.23 72.0
xmlns: http://www.w3.org/2000/svg
version:
<style> blocks: 0
<g> groups: 0
--- BACKGROUND (1 path elements) ---
path[0]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=55, class='', fill='#000000'
--- WHITE (13 path elements) ---
path[0]: 19 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=399, class='', fill='#ffffff'
path[1]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=116, class='', fill='#ffffff'
path[2]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=139, class='', fill='#ffffff'
path[3]: 5 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=33, class='', fill='#ffffff'
path[4]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=352, class='', fill='#ffffff'
path[5]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=551, class='', fill='#ffffff'
path[6]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=818, class='', fill='#ffffff'
path[7]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=133, class='', fill='#ffffff'
path[8]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=252, class='', fill='#ffffff'
path[9]: 12 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=484, class='', fill='#ffffff'
path[10]: 5 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=55, class='', fill='#ffffff'
path[11]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=705, class='', fill='#ffffff'
path[12]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1147, class='', fill='#ffffff'
--- CYAN (37 path elements) ---
path[0]: 65 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=895, class='', fill='#00aeef'
path[1]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=97, class='', fill='#00aeef'
path[2]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=733, class='', fill='#00aeef'
path[3]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=466, class='', fill='#00aeef'
path[4]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=393, class='', fill='#00aeef'
path[5]: 23 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=983, class='', fill='#00aeef'
path[6]: 13 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=173, class='', fill='#00aeef'
path[7]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=689, class='', fill='#00aeef'
path[8]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=371, class='', fill='#00aeef'
path[9]: 5 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=36, class='', fill='#00aeef'
path[10]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=488, class='', fill='#00aeef'
path[11]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1105, class='', fill='#00aeef'
path[12]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=383, class='', fill='#00aeef'
path[13]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=142, class='', fill='#00aeef'
path[14]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=283, class='', fill='#00aeef'
path[15]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=793, class='', fill='#00aeef'
path[16]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=628, class='', fill='#00aeef'
path[17]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=551, class='', fill='#00aeef'
path[18]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=638, class='', fill='#00aeef'
path[19]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=253, class='', fill='#00aeef'
path[20]: 19 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=380, class='', fill='#00aeef'
path[21]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=697, class='', fill='#00aeef'
path[22]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=366, class='', fill='#00aeef'
path[23]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=881, class='', fill='#00aeef'
path[24]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=118, class='', fill='#00aeef'
path[25]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1126, class='', fill='#00aeef'
path[26]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1210, class='', fill='#00aeef'
path[27]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1230, class='', fill='#00aeef'
path[28]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=473, class='', fill='#00aeef'
path[29]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=886, class='', fill='#00aeef'
path[30]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=945, class='', fill='#00aeef'
path[31]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=847, class='', fill='#00aeef'
path[32]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=451, class='', fill='#00aeef'
path[33]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=523, class='', fill='#00aeef'
path[34]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=334, class='', fill='#00aeef'
path[35]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=886, class='', fill='#00aeef'
path[36]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=461, class='', fill='#00aeef'
======================================================================
[NEW] KarenPeterson_nametag.svg
======================================================================
viewBox: 0 0 221.23 72.0
xmlns: http://www.w3.org/2000/svg
version:
<style> blocks: 0
<g> groups: 0
--- BACKGROUND (1 path elements) ---
path[0]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=55, class='', fill='#000000'
--- WHITE (17 path elements) ---
path[0]: 19 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=399, class='', fill='#ffffff'
path[1]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=116, class='', fill='#ffffff'
path[2]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=139, class='', fill='#ffffff'
path[3]: 5 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=33, class='', fill='#ffffff'
path[4]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=186, class='', fill='#ffffff'
path[5]: 13 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=193, class='', fill='#ffffff'
path[6]: 19 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=408, class='', fill='#ffffff'
path[7]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=157, class='', fill='#ffffff'
path[8]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=143, class='', fill='#ffffff'
path[9]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=479, class='', fill='#ffffff'
path[10]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=892, class='', fill='#ffffff'
path[11]: 17 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=582, class='', fill='#ffffff'
path[12]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=992, class='', fill='#ffffff'
path[13]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=325, class='', fill='#ffffff'
path[14]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1351, class='', fill='#ffffff'
path[15]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close'}, d-len=924, class='', fill='#ffffff'
path[16]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=478, class='', fill='#ffffff'
--- CYAN (37 path elements) ---
path[0]: 65 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=895, class='', fill='#00aeef'
path[1]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=559, class='', fill='#00aeef'
path[2]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=856, class='', fill='#00aeef'
path[3]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=229, class='', fill='#00aeef'
path[4]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=605, class='', fill='#00aeef'
path[5]: 9 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=75, class='', fill='#00aeef'
path[6]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=827, class='', fill='#00aeef'
path[7]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1140, class='', fill='#00aeef'
path[8]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=845, class='', fill='#00aeef'
path[9]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=796, class='', fill='#00aeef'
path[10]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=892, class='', fill='#00aeef'
path[11]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=871, class='', fill='#00aeef'
path[12]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=314, class='', fill='#00aeef'
path[13]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=827, class='', fill='#00aeef'
path[14]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=152, class='', fill='#00aeef'
path[15]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=463, class='', fill='#00aeef'
path[16]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1269, class='', fill='#00aeef'
path[17]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=613, class='', fill='#00aeef'
path[18]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=902, class='', fill='#00aeef'
path[19]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=313, class='', fill='#00aeef'
path[20]: 19 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=380, class='', fill='#00aeef'
path[21]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=697, class='', fill='#00aeef'
path[22]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=366, class='', fill='#00aeef'
path[23]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=881, class='', fill='#00aeef'
path[24]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=118, class='', fill='#00aeef'
path[25]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1126, class='', fill='#00aeef'
path[26]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1210, class='', fill='#00aeef'
path[27]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1230, class='', fill='#00aeef'
path[28]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=473, class='', fill='#00aeef'
path[29]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=886, class='', fill='#00aeef'
path[30]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=945, class='', fill='#00aeef'
path[31]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=847, class='', fill='#00aeef'
path[32]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=451, class='', fill='#00aeef'
path[33]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=523, class='', fill='#00aeef'
path[34]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=334, class='', fill='#00aeef'
path[35]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=886, class='', fill='#00aeef'
path[36]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=461, class='', fill='#00aeef'
======================================================================
[NEW] KarenPeterson_nametag_1.svg
======================================================================
viewBox: 0 0 221.23 72.0
xmlns: http://www.w3.org/2000/svg
version:
<style> blocks: 0
<g> groups: 0
--- BACKGROUND (1 path elements) ---
path[0]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=55, class='', fill='#000000'
--- WHITE (17 path elements) ---
path[0]: 19 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=399, class='', fill='#ffffff'
path[1]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=116, class='', fill='#ffffff'
path[2]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=139, class='', fill='#ffffff'
path[3]: 5 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=33, class='', fill='#ffffff'
path[4]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=186, class='', fill='#ffffff'
path[5]: 13 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=193, class='', fill='#ffffff'
path[6]: 19 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=408, class='', fill='#ffffff'
path[7]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=157, class='', fill='#ffffff'
path[8]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=143, class='', fill='#ffffff'
path[9]: 16 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=479, class='', fill='#ffffff'
path[10]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=892, class='', fill='#ffffff'
path[11]: 17 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=582, class='', fill='#ffffff'
path[12]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=992, class='', fill='#ffffff'
path[13]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=325, class='', fill='#ffffff'
path[14]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1351, class='', fill='#ffffff'
path[15]: 12 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close'}, d-len=924, class='', fill='#ffffff'
path[16]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=478, class='', fill='#ffffff'
--- CYAN (37 path elements) ---
path[0]: 65 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=895, class='', fill='#00aeef'
path[1]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=559, class='', fill='#00aeef'
path[2]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=856, class='', fill='#00aeef'
path[3]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=229, class='', fill='#00aeef'
path[4]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=605, class='', fill='#00aeef'
path[5]: 9 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=75, class='', fill='#00aeef'
path[6]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=827, class='', fill='#00aeef'
path[7]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1140, class='', fill='#00aeef'
path[8]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=845, class='', fill='#00aeef'
path[9]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=796, class='', fill='#00aeef'
path[10]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=892, class='', fill='#00aeef'
path[11]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=871, class='', fill='#00aeef'
path[12]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=314, class='', fill='#00aeef'
path[13]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=827, class='', fill='#00aeef'
path[14]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=152, class='', fill='#00aeef'
path[15]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=463, class='', fill='#00aeef'
path[16]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1269, class='', fill='#00aeef'
path[17]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=613, class='', fill='#00aeef'
path[18]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=902, class='', fill='#00aeef'
path[19]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=313, class='', fill='#00aeef'
path[20]: 19 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=380, class='', fill='#00aeef'
path[21]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=697, class='', fill='#00aeef'
path[22]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=366, class='', fill='#00aeef'
path[23]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=881, class='', fill='#00aeef'
path[24]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=118, class='', fill='#00aeef'
path[25]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1126, class='', fill='#00aeef'
path[26]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1210, class='', fill='#00aeef'
path[27]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1230, class='', fill='#00aeef'
path[28]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=473, class='', fill='#00aeef'
path[29]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=886, class='', fill='#00aeef'
path[30]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=945, class='', fill='#00aeef'
path[31]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=847, class='', fill='#00aeef'
path[32]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=451, class='', fill='#00aeef'
path[33]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=523, class='', fill='#00aeef'
path[34]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=334, class='', fill='#00aeef'
path[35]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=886, class='', fill='#00aeef'
path[36]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=461, class='', fill='#00aeef'
======================================================================
[NEW] MonicaMillen_nametag.svg
======================================================================
viewBox: 0 0 221.23 72.0
xmlns: http://www.w3.org/2000/svg
version:
<style> blocks: 0
<g> groups: 0
--- BACKGROUND (1 path elements) ---
path[0]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=55, class='', fill='#000000'
--- WHITE (12 path elements) ---
path[0]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=185, class='', fill='#ffffff'
path[1]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=610, class='', fill='#ffffff'
path[2]: 11 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=167, class='', fill='#ffffff'
path[3]: 5 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=47, class='', fill='#ffffff'
path[4]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=549, class='', fill='#ffffff'
path[5]: 13 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=176, class='', fill='#ffffff'
path[6]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=190, class='', fill='#ffffff'
path[7]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=140, class='', fill='#ffffff'
path[8]: 5 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=56, class='', fill='#ffffff'
path[9]: 5 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=66, class='', fill='#ffffff'
path[10]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=992, class='', fill='#ffffff'
path[11]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=490, class='', fill='#ffffff'
--- CYAN (18 path elements) ---
path[0]: 65 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=895, class='', fill='#00aeef'
path[1]: 13 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=153, class='', fill='#00aeef'
path[2]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=895, class='', fill='#00aeef'
path[3]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=857, class='', fill='#00aeef'
path[4]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=125, class='', fill='#00aeef'
path[5]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1210, class='', fill='#00aeef'
path[6]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=595, class='', fill='#00aeef'
path[7]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1230, class='', fill='#00aeef'
path[8]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=458, class='', fill='#00aeef'
path[9]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=604, class='', fill='#00aeef'
path[10]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=583, class='', fill='#00aeef'
path[11]: 7 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=80, class='', fill='#00aeef'
path[12]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=723, class='', fill='#00aeef'
path[13]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=315, class='', fill='#00aeef'
path[14]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=256, class='', fill='#00aeef'
path[15]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=148, class='', fill='#00aeef'
path[16]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=869, class='', fill='#00aeef'
path[17]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1249, class='', fill='#00aeef'
======================================================================
[NEW] SammieWyles_nametag.svg
======================================================================
viewBox: 0 0 221.23 72.0
xmlns: http://www.w3.org/2000/svg
version:
<style> blocks: 0
<g> groups: 0
--- BACKGROUND (1 path elements) ---
path[0]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=55, class='', fill='#000000'
--- WHITE (15 path elements) ---
path[0]: 19 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=399, class='', fill='#ffffff'
path[1]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=116, class='', fill='#ffffff'
path[2]: 8 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=139, class='', fill='#ffffff'
path[3]: 5 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=33, class='', fill='#ffffff'
path[4]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=833, class='', fill='#ffffff'
path[5]: 13 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=173, class='', fill='#ffffff'
path[6]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=188, class='', fill='#ffffff'
path[7]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=207, class='', fill='#ffffff'
path[8]: 5 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=47, class='', fill='#ffffff'
path[9]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=126, class='', fill='#ffffff'
path[10]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=252, class='', fill='#ffffff'
path[11]: 12 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=484, class='', fill='#ffffff'
path[12]: 5 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=55, class='', fill='#ffffff'
path[13]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=705, class='', fill='#ffffff'
path[14]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1147, class='', fill='#ffffff'
--- CYAN (40 path elements) ---
path[0]: 65 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=895, class='', fill='#00aeef'
path[1]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=227, class='', fill='#00aeef'
path[2]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=998, class='', fill='#00aeef'
path[3]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=571, class='', fill='#00aeef'
path[4]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=558, class='', fill='#00aeef'
path[5]: 23 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1526, class='', fill='#00aeef'
path[6]: 13 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=289, class='', fill='#00aeef'
path[7]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1060, class='', fill='#00aeef'
path[8]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=583, class='', fill='#00aeef'
path[9]: 5 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=67, class='', fill='#00aeef'
path[10]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=705, class='', fill='#00aeef'
path[11]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1511, class='', fill='#00aeef'
path[12]: 13 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=301, class='', fill='#00aeef'
path[13]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1513, class='', fill='#00aeef'
path[14]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1510, class='', fill='#00aeef'
path[15]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1019, class='', fill='#00aeef'
path[16]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1036, class='', fill='#00aeef'
path[17]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=158, class='', fill='#00aeef'
path[18]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1503, class='', fill='#00aeef'
path[19]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=701, class='', fill='#00aeef'
path[20]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1180, class='', fill='#00aeef'
path[21]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=625, class='', fill='#00aeef'
path[22]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=158, class='', fill='#00aeef'
path[23]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=356, class='', fill='#00aeef'
path[24]: 18 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1173, class='', fill='#00aeef'
path[25]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1035, class='', fill='#00aeef'
path[26]: 18 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=700, class='', fill='#00aeef'
path[27]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1025, class='', fill='#00aeef'
path[28]: 10 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=359, class='', fill='#00aeef'
path[29]: 12 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=305, class='', fill='#00aeef'
path[30]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=356, class='', fill='#00aeef'
path[31]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=105, class='', fill='#00aeef'
path[32]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=855, class='', fill='#00aeef'
path[33]: 13 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=458, class='', fill='#00aeef'
path[34]: 20 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1252, class='', fill='#00aeef'
path[35]: 15 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=870, class='', fill='#00aeef'
path[36]: 14 segments, 1 loops, 1 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=886, class='', fill='#00aeef'
path[37]: 10 segments, 2 loops, 2 M-commands, types={'Move', 'Close', 'Line'}, d-len=152, class='', fill='#00aeef'
path[38]: 22 segments, 2 loops, 2 M-commands, types={'Move', 'CubicBezier', 'Close', 'Line'}, d-len=1269, class='', fill='#00aeef'
path[39]: 5 segments, 1 loops, 1 M-commands, types={'Move', 'Close', 'Line'}, d-len=56, class='', fill='#00aeef'

View File

@@ -27,9 +27,11 @@ def setup_args():
parser = argparse.ArgumentParser(description='Convert SVGs to Nametag STLs')
parser.add_argument('input_dir', help='Directory containing SVG files')
parser.add_argument('--output-dir', help='Output directory for STLs', default=None)
parser.add_argument('--format', choices=['auto', 'old', 'new'], default='auto',
help='SVG format: old (class-based), new (ID-based), auto (detect)')
return parser.parse_args()
def get_paths_from_svg(svg_file):
def get_paths_from_svg(svg_file, format_type='auto'):
"""
Parses the SVG file and separates paths into Background, White, and Cyan.
Returns a dictionary with list of svg.path objects.
@@ -41,6 +43,14 @@ def get_paths_from_svg(svg_file):
'cyan': []
}
# Auto-detect format based on the presence of <style>
if format_type == 'auto':
style_elements = doc.getElementsByTagName('style')
if len(style_elements) > 0:
format_type = 'old'
else:
format_type = 'new'
# Process all path elements
for path_node in doc.getElementsByTagName('path'):
d_str = path_node.getAttribute('d')
@@ -55,17 +65,25 @@ def get_paths_from_svg(svg_file):
logger.warning(f"Failed to parse path in {svg_file}: {e}")
continue
# Classify based on your specs
if class_str == CLASS_WHITE:
paths['white'].append(path_obj)
elif class_str == CLASS_CYAN:
paths['cyan'].append(path_obj)
else:
# Assume no class or other classes are background/outline
# But specifically, look for the main outline which usually has no class or a specific structure
# based on your SVG, the background is the first path with no class.
# We will treat any non-color path as background for now, or refine if needed.
paths['background'].append(path_obj)
if format_type == 'old':
if class_str == CLASS_WHITE:
paths['white'].append(path_obj)
elif class_str == CLASS_CYAN:
paths['cyan'].append(path_obj)
else:
paths['background'].append(path_obj)
else: # new format
parent = path_node.parentNode
parent_id = parent.getAttribute('id') if parent and parent.nodeType == parent.ELEMENT_NODE else ""
if parent_id == 'white-text':
paths['white'].append(path_obj)
elif parent_id == 'cyan-logo-text':
paths['cyan'].append(path_obj)
elif parent_id == 'background':
paths['background'].append(path_obj)
else:
paths['background'].append(path_obj) # Fallback
doc.unlink()
return paths
@@ -213,13 +231,13 @@ def create_extrusion(paths, height, z_offset=0.0, scale=1.0):
logger.error(f"Extrusion failed: {e}")
return None
def process_file(filepath, output_dir):
def process_file(filepath, output_dir, format_type='auto'):
filename = os.path.basename(filepath)
base_name = os.path.splitext(filename)[0]
logger.info(f"Processing {filename}...")
logger.info(f"Processing {filename} (Format: {format_type})...")
paths = get_paths_from_svg(filepath)
paths = get_paths_from_svg(filepath, format_type)
parts = {
'Black': {'paths': paths['background'], 'height': BACKGROUND_THICKNESS, 'z': 0.0},
@@ -287,7 +305,7 @@ def main():
for full_path in files_to_process:
try:
process_file(full_path, output_dir)
process_file(full_path, output_dir, format_type=args.format)
except Exception as e:
import traceback
logger.error(f"Failed to process {full_path}: {e}")

27
old-new-diff.MD Normal file
View File

@@ -0,0 +1,27 @@
# Format Migration: Old to New 2.0
## Format Comparison
| Feature | Old Format (`nametags/`) | New 1.0 (`input/`) | **New 2.0 (`new/`) - Target** |
|---------|------------------------|--------------------|--------------------------------|
| **Grouping** | `<g>` layers (Illustrator) | Flat (no `<g>` tags) | **Semantic `<g>` tags with `id` attributes** |
| **Coloring** | `<style>` + classes (`st1`) | Inline `fill="#00aeef"` | Inline `fill` |
| **Classification Signal**| `class="st1"` / `st2` | `fill="#00aeef"` / `#fff` | **Parent `<g>` tag `id`** (`background`, `white-text`, `cyan-logo-text`) |
## Key Differences Summary
### Structural Changes
- **Old**: Relies on `<g>` layers with Illustrator-generated classes like `st1`, `st2`
- **New 1.0**: Flattened structure with inline color values but no semantic grouping
- **New 2.0**: Semantic `<g>` tags with explicit `id` attributes on parent groups for robust classification
### Classification Logic Changes
- **Old Format**: Uses `class="st1"` / `st2` attribute checks
- **New 1.0 Format**: Uses inline `fill` color hex values (`#00aeef` / `#fff`)
- **New 2.0 Format**: Uses parent `<g>` tag `id` attributes with semantic names (`background`, `white-text`, `cyan-logo-text`)
### Advantages of New 2.0 Format
- Cleanest classification method using semantic grouping
- More robust than exact color hex value matching
- Better than relying on historical Illustrator class names (`st1`, `st2`)
- Explicit functional layer grouping rather than color-based classification

111
test_parse.py Normal file
View File

@@ -0,0 +1,111 @@
"""
Analyze the structural differences between old and new SVG formats
to determine impact on the 3D generation pipeline.
"""
import os
from xml.dom import minidom
from svg.path import parse_path
CLASS_WHITE = 'st2'
CLASS_CYAN = 'st1'
def analyze_svg(filepath, label):
filename = os.path.basename(filepath)
print(f"\n{'='*70}")
print(f"[{label}] {filename}")
print(f"{'='*70}")
doc = minidom.parse(filepath)
# Check SVG root attributes
svg_el = doc.getElementsByTagName('svg')[0]
print(f" viewBox: {svg_el.getAttribute('viewBox')}")
print(f" xmlns: {svg_el.getAttribute('xmlns')}")
print(f" version: {svg_el.getAttribute('version')}")
# Check for <style> block
style_els = doc.getElementsByTagName('style')
print(f" <style> blocks: {len(style_els)}")
# Check for <g> grouping
g_els = doc.getElementsByTagName('g')
print(f" <g> groups: {len(g_els)}")
# Check for non-path elements
for tag in ['text', 'rect', 'circle', 'ellipse', 'line', 'polyline', 'polygon']:
els = doc.getElementsByTagName(tag)
if els:
print(f" <{tag}> elements: {len(els)}")
# Analyze paths
paths_by_category = {'background': [], 'white': [], 'cyan': []}
for path_node in doc.getElementsByTagName('path'):
d_str = path_node.getAttribute('d')
class_str = path_node.getAttribute('class')
fill_str = path_node.getAttribute('fill')
if not d_str:
continue
fill_color = fill_str.lower().strip() if fill_str else ""
# Categorize
if class_str == CLASS_WHITE or fill_color in ['#ffffff', '#fff', 'white']:
cat = 'white'
elif class_str == CLASS_CYAN or fill_color in ['#00aeef', 'cyan']:
cat = 'cyan'
else:
cat = 'background'
# Parse the path and analyze its structure
try:
path_obj = parse_path(d_str)
segments = list(path_obj)
seg_types = [s.__class__.__name__ for s in segments]
# Count sub-paths (loops) via discontinuities
loop_count = 1
for i in range(1, len(segments)):
if abs(segments[i].start - segments[i-1].end) > 1e-4:
loop_count += 1
# Count M commands in raw d string
m_count = d_str.upper().count('M')
paths_by_category[cat].append({
'seg_count': len(segments),
'loop_count': loop_count,
'm_count': m_count,
'seg_types': set(seg_types),
'd_length': len(d_str),
'class': class_str,
'fill': fill_str,
})
except Exception as e:
print(f" ERROR parsing path: {e}")
for cat_name, cat_paths in paths_by_category.items():
print(f"\n --- {cat_name.upper()} ({len(cat_paths)} path elements) ---")
for i, p in enumerate(cat_paths):
print(f" path[{i}]: {p['seg_count']} segments, {p['loop_count']} loops, "
f"{p['m_count']} M-commands, types={p['seg_types']}, "
f"d-len={p['d_length']}, class='{p['class']}', fill='{p['fill']}'")
doc.unlink()
# Analyze old format files
print("\n" + "#"*70)
print("# OLD FORMAT FILES (nametags/)")
print("#"*70)
for f in sorted(os.listdir(r"S:\svg2nametagCLI\nametags")):
if f.endswith('.svg'):
analyze_svg(os.path.join(r"S:\svg2nametagCLI\nametags", f), "OLD")
# Analyze new format files
print("\n" + "#"*70)
print("# NEW FORMAT FILES (input/)")
print("#"*70)
for f in sorted(os.listdir(r"S:\svg2nametagCLI\input")):
if f.endswith('.svg'):
analyze_svg(os.path.join(r"S:\svg2nametagCLI\input", f), "NEW")

39
test_parse2.py Normal file
View File

@@ -0,0 +1,39 @@
from xml.dom import minidom
import glob
def analyze_format(file_path):
print(f"\nAnalyzing: {file_path}")
doc = minidom.parse(file_path)
g_tags = doc.getElementsByTagName('g')
print(f"Number of <g> tags: {len(g_tags)}")
for g in g_tags:
print(f" <g id='{g.getAttribute('id')}' class='{g.getAttribute('class')}'>")
path_tags = doc.getElementsByTagName('path')
print(f"Number of <path> tags: {len(path_tags)}")
bg_paths = 0
white_paths = 0
cyan_paths = 0
unknown_paths = 0
for p in path_tags:
parent = p.parentNode
parent_id = parent.getAttribute('id') if parent else ""
if parent_id == "background":
bg_paths += 1
elif parent_id == "white-text":
white_paths += 1
elif parent_id == "cyan-logo-text":
cyan_paths += 1
else:
unknown_paths += 1
print(f"Path distribution by <g> id:")
print(f" background: {bg_paths}")
print(f" white-text: {white_paths}")
print(f" cyan-logo-text: {cyan_paths}")
print(f" unknown/no-group: {unknown_paths}")
analyze_format(r'S:\svg2nametagCLI\new\SammieWyles_nametag.svg')

24
webapp/.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

29
webapp/Dockerfile Normal file
View File

@@ -0,0 +1,29 @@
# Build stage
FROM node:18-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Production stage
FROM nginx:stable-alpine
# Copy the build output
COPY --from=build /app/dist /usr/share/nginx/html
# Custom nginx config to handle WASM and SPA routing
RUN printf "server {\n\
listen 80;\n\
location / {\n\
root /usr/share/nginx/html;\n\
index index.html;\n\
try_files \$uri \$uri/ /index.html;\n\
}\n\
location ~* \\.wasm$ {\n\
root /usr/share/nginx/html;\n\
default_type application/wasm;\n\
}\n\
}" > /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

16
webapp/README.md Normal file
View File

@@ -0,0 +1,16 @@
# React + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
## React Compiler
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
## Expanding the ESLint configuration
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.

View File

@@ -0,0 +1 @@
if('serviceWorker' in navigator) navigator.serviceWorker.register('/dev-sw.js?dev-sw', { scope: '/', type: 'classic' })

92
webapp/dev-dist/sw.js Normal file
View File

@@ -0,0 +1,92 @@
/**
* Copyright 2018 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// If the loader is already loaded, just stop.
if (!self.define) {
let registry = {};
// Used for `eval` and `importScripts` where we can't get script URL by other means.
// In both cases, it's safe to use a global var because those functions are synchronous.
let nextDefineUri;
const singleRequire = (uri, parentUri) => {
uri = new URL(uri + ".js", parentUri).href;
return registry[uri] || (
new Promise(resolve => {
if ("document" in self) {
const script = document.createElement("script");
script.src = uri;
script.onload = resolve;
document.head.appendChild(script);
} else {
nextDefineUri = uri;
importScripts(uri);
resolve();
}
})
.then(() => {
let promise = registry[uri];
if (!promise) {
throw new Error(`Module ${uri} didn’t register its module`);
}
return promise;
})
);
};
self.define = (depsNames, factory) => {
const uri = nextDefineUri || ("document" in self ? document.currentScript.src : "") || location.href;
if (registry[uri]) {
// Module is already loading or loaded.
return;
}
let exports = {};
const require = depUri => singleRequire(depUri, uri);
const specialDeps = {
module: { uri },
exports,
require
};
registry[uri] = Promise.all(depsNames.map(
depName => specialDeps[depName] || require(depName)
)).then(deps => {
factory(...deps);
return exports;
});
};
}
define(['./workbox-5a5d9309'], (function (workbox) { 'use strict';
self.skipWaiting();
workbox.clientsClaim();
/**
* The precacheAndRoute() method efficiently caches and responds to
* requests for URLs in the manifest.
* See https://goo.gl/S9QRab
*/
workbox.precacheAndRoute([{
"url": "registerSW.js",
"revision": "3ca0b8505b4bec776b69afdba2768812"
}, {
"url": "index.html",
"revision": "0.5auj614cprc"
}], {});
workbox.cleanupOutdatedCaches();
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
allowlist: [/^\/$/]
}));
}));

File diff suppressed because it is too large Load Diff

29
webapp/eslint.config.js Normal file
View File

@@ -0,0 +1,29 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import { defineConfig, globalIgnores } from 'eslint/config'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{js,jsx}'],
extends: [
js.configs.recommended,
reactHooks.configs.flat.recommended,
reactRefresh.configs.vite,
],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
ecmaVersion: 'latest',
ecmaFeatures: { jsx: true },
sourceType: 'module',
},
},
rules: {
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
},
},
])

20
webapp/index.html Normal file
View File

@@ -0,0 +1,20 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/png" href="/favicon.ico" />
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
<link rel="apple-touch-icon" href="/pwa-192x192.png" />
<meta name="theme-color" content="#1a1a1a" />
<meta name="description" content="Convert SVG files to 3D printable nametags offline." />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SVG to Nametag Converter</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

8348
webapp/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

37
webapp/package.json Normal file
View File

@@ -0,0 +1,37 @@
{
"name": "webapp",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@react-three/drei": "^10.7.7",
"@react-three/fiber": "^9.5.0",
"file-saver": "^2.0.5",
"jszip": "^3.10.1",
"manifold-3d": "^3.3.2",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react-dropzone": "^15.0.0",
"react-icons": "^5.5.0",
"svg-path-parser": "^1.1.0",
"three": "^0.182.0",
"vite-plugin-pwa": "^1.2.0"
},
"devDependencies": {
"@eslint/js": "^9.39.1",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.1",
"eslint": "^9.39.1",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.4.24",
"globals": "^16.5.0",
"vite": "^7.3.1"
}
}

BIN
webapp/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
webapp/public/manifold.wasm Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

246
webapp/src/App.css Normal file
View File

@@ -0,0 +1,246 @@
:root {
--primary: #00aeef;
--primary-hover: #0090c5;
--bg-dark: #1a1a1a;
--bg-panel: #2a2a2a;
--text-main: #ffffff;
--text-muted: #aaaaaa;
--border: #444;
}
body {
margin: 0;
font-family: 'Inter', system-ui, Avenir, Helvetica, Arial, sans-serif;
background-color: var(--bg-dark);
color: var(--text-main);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.container {
width: 100%;
max-width: 800px;
padding: 2rem;
display: flex;
flex-direction: column;
gap: 2rem;
}
main {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
header {
text-align: center;
position: relative;
}
.git-link {
position: absolute;
top: 0;
right: 0;
font-size: 0.75rem;
color: var(--text-muted);
text-decoration: none;
opacity: 0.6;
transition: opacity 0.2s;
}
.git-link:hover {
opacity: 1;
}
header h1 {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
margin-bottom: 0.5rem;
color: var(--primary);
}
.icon-spin {
animation: spin 4s linear infinite;
}
.dropzone {
background: var(--bg-panel);
border: 2px dashed var(--border);
border-radius: 12px;
padding: 3rem;
text-align: center;
cursor: pointer;
transition: all 0.2s ease;
position: relative;
/* For folder button positioning */
}
.folder-select-btn {
position: absolute;
top: 1rem;
right: 1rem;
background: rgba(255, 255, 255, 0.05);
/* Slight visibility */
border: 1px solid var(--border);
border-radius: 8px;
padding: 0.5rem;
color: var(--text-muted);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
z-index: 10;
}
.folder-select-btn:hover {
background: var(--primary);
color: white;
border-color: var(--primary);
transform: scale(1.05);
}
.dropzone:hover,
.dropzone.active {
border-color: var(--primary);
background: rgba(0, 174, 239, 0.05);
}
.dropzone-content h3 {
margin: 1rem 0 0.5rem;
}
.dropzone-content p {
color: var(--text-muted);
margin: 0;
}
.controls {
background: var(--bg-panel);
padding: 1.5rem;
border-radius: 12px;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 1rem;
}
.status {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.engine-status {
font-size: 0.85rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.ready {
color: #4caf50;
display: flex;
align-items: center;
gap: 4px;
}
.loading {
color: #ff9800;
display: flex;
align-items: center;
gap: 4px;
}
.buttons {
display: flex;
gap: 1rem;
}
button {
border: none;
border-radius: 8px;
padding: 0.75rem 1.5rem;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
display: flex;
align-items: center;
gap: 0.5rem;
transition: background 0.2s;
}
.btn-primary {
background: var(--primary);
color: white;
}
.btn-primary:hover:not(:disabled) {
background: var(--primary-hover);
}
.btn-secondary {
background: transparent;
border: 1px solid var(--border);
color: var(--text-muted);
}
.btn-secondary:hover:not(:disabled) {
border-color: var(--text-main);
color: var(--text-main);
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.logs-panel {
background: #000;
border-radius: 8px;
padding: 1rem;
font-family: monospace;
height: 200px;
overflow: hidden;
display: flex;
flex-direction: column;
}
.logs-panel h4 {
margin: 0 0 0.5rem 0;
color: var(--text-muted);
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 1px;
}
.logs-content {
overflow-y: auto;
flex: 1;
font-size: 0.9rem;
color: #0f0;
}
.log-entry {
margin-bottom: 2px;
}
.placeholder {
color: #444;
font-style: italic;
}
@keyframes spin {
100% {
transform: rotate(360deg);
}
}
.spin {
animation: spin 1s linear infinite;
}

173
webapp/src/App.jsx Normal file
View File

@@ -0,0 +1,173 @@
import { useState, useCallback } from 'react'
import { useDropzone } from 'react-dropzone'
import { saveAs } from 'file-saver'
import JSZip from 'jszip'
import { FaCloudUploadAlt, FaFileExport, FaCheckCircle, FaSpinner, FaTrash } from 'react-icons/fa'
import { MdError, Md3dRotation, MdFolderOpen } from 'react-icons/md'
import './App.css'
import { useManifold, convertFile } from './logic/useNametagConverter'
function App() {
const manifold = useManifold()
const [files, setFiles] = useState([])
const [processing, setProcessing] = useState(false)
const [logs, setLogs] = useState([])
const addLog = (msg) => setLogs(prev => [...prev, msg])
const onDrop = useCallback(acceptedFiles => {
// Filter for SVGs
const svgs = acceptedFiles.filter(f => f.name.toLowerCase().endsWith('.svg') && !f.name.startsWith('._'))
setFiles(prev => [...prev, ...svgs])
addLog(`Added ${svgs.length} SVG files to queue.`)
}, [])
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop })
const onFolderSelect = (e) => {
if (e.target.files && e.target.files.length > 0) {
const selectedFiles = Array.from(e.target.files);
const svgs = selectedFiles.filter(f => f.name.toLowerCase().endsWith('.svg') && !f.name.startsWith('._') && !f.name.startsWith('.'));
if (svgs.length > 0) {
setFiles(prev => [...prev, ...svgs]);
addLog(`Added ${svgs.length} SVG files from folder.`);
} else {
addLog(`No SVG files found in selected folder.`);
}
}
// Reset
e.target.value = null;
}
const processQueue = async () => {
if (!manifold) {
alert("WASM Engine still loading... please wait a moment.")
return
}
setProcessing(true)
const zip = new JSZip()
let successCount = 0;
try {
for (const file of files) {
try {
addLog(`Processing ${file.name}...`)
const result = await convertFile(file, manifold, addLog)
if (result) {
const folderName = file.name.replace('.svg', '')
const folder = zip.folder(folderName)
// Add STLs to zip
if (result.black) folder.file(`${folderName}_Black.stl`, result.black)
if (result.white) folder.file(`${folderName}_White.stl`, result.white)
if (result.cyan) folder.file(`${folderName}_Cyan.stl`, result.cyan)
addLog(` Success!`)
successCount++;
}
} catch (e) {
console.error(e)
addLog(` Error: ${e.message}`)
}
}
if (successCount > 0) {
addLog("Generating ZIP archive...")
const content = await zip.generateAsync({ type: "blob" })
saveAs(content, "Nametags_Converted.zip")
addLog("Download started.")
} else {
addLog("No files were successfully converted.")
}
} catch (err) {
addLog(`Critical Error: ${err.message}`)
} finally {
setProcessing(false)
}
}
return (
<div className="container">
<header>
<h1><Md3dRotation className="icon-spin" /> SVG to Nametag Converter</h1>
<p>Powered by WebAssembly & Manifold 3D</p>
<a href="https://warehouse.randomhack.com/unfunny/svg2NameTag-Ren/src/branch/web-app/" target="_blank" rel="noopener noreferrer" className="git-link">View Source</a>
</header>
<main>
<div {...getRootProps()} className={`dropzone ${isDragActive ? 'active' : ''}`}>
<input {...getInputProps()} />
{/* Folder Selection Button */}
<div
className="folder-select-btn"
onClick={(e) => e.stopPropagation()}
title="Select Folder to Batch Process"
>
<label htmlFor="folder-input" style={{ cursor: 'pointer', display: 'flex' }}>
<MdFolderOpen size={28} />
</label>
<input
id="folder-input"
type="file"
webkitdirectory=""
directory=""
multiple
style={{ display: 'none' }}
onChange={onFolderSelect}
/>
</div>
<div className="dropzone-content">
<FaCloudUploadAlt size={64} color={isDragActive ? "#00aeef" : "#666"} />
{isDragActive ?
<h3>Drop files to add specifically...</h3> :
<>
<h3>Drag & Drop SVGs Here</h3>
<p>Running directly in your browser. Secure & Fast.</p>
</>
}
</div>
</div>
<div className="controls">
<div className="status">
Queue: <strong>{files.length}</strong> files
<span className="engine-status">
{manifold ? <span className="ready"><FaCheckCircle /> Engine Ready</span> : <span className="loading"><FaSpinner className="spin" /> Loading Engine...</span>}
</span>
</div>
<div className="buttons">
<button
className="btn-primary"
onClick={processQueue}
disabled={processing || files.length === 0 || !manifold}
>
{processing ? <><FaSpinner className="spin" /> Converting...</> : <><FaFileExport /> Convert & Download ZIP</>}
</button>
<button
className="btn-secondary"
onClick={() => { setFiles([]); setLogs([]); }}
disabled={processing}
>
<FaTrash /> Clear Queue
</button>
</div>
</div>
<div className="logs-panel">
<h4>Activity Log</h4>
<div className="logs-content">
{logs.length === 0 ? <span className="placeholder">Logs will appear here...</span> : logs.map((l, i) => <div key={i} className="log-entry">{l}</div>)}
</div>
</div>
</main>
</div>
)
}
export default App

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

68
webapp/src/index.css Normal file
View File

@@ -0,0 +1,68 @@
:root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}

View File

@@ -0,0 +1,201 @@
import { useEffect, useState } from 'react';
import Module from 'manifold-3d';
import { parseSVG } from 'svg-path-parser';
import * as THREE from 'three';
import { STLExporter } from 'three/examples/jsm/exporters/STLExporter';
// Initialize Manifold WASM once
let wasmModule;
export const useManifold = () => {
const [manifold, setManifold] = useState(null);
useEffect(() => {
const init = async () => {
try {
if (!wasmModule) {
// Fix: Explicitly tell Manifold where to find the WASM file
// distinct from the bundle path
wasmModule = await Module({
locateFile: (path) => {
if (path.endsWith('.wasm')) {
return '/manifold.wasm';
}
return path;
}
});
wasmModule.setup();
}
setManifold(wasmModule);
} catch (e) {
console.error("WASM Init Failed:", e);
// We could set an error state here, but for now logging prevents crash
}
};
init();
}, []);
return manifold;
};
// --- Geometry Helpers ---
const getPathPoints = (d, scale = 1.0) => {
// 1. Parse SVG path data using browser native API
const pathEl = document.createElementNS("http://www.w3.org/2000/svg", "path");
pathEl.setAttribute("d", d);
const len = pathEl.getTotalLength();
if (len < 0.1) return [];
const resolution = 0.5; // mm approx
const numPoints = Math.max(10, Math.ceil(len / resolution));
const loops = [];
let currentLoop = [];
let lastP = null;
for (let i = 0; i <= numPoints; i++) {
const p = pathEl.getPointAtLength((i / numPoints) * len);
if (lastP) {
const dist = Math.hypot(p.x - lastP.x, p.y - lastP.y);
// Detect "Move" command jumps which signify new subpaths
if (dist > 5.0) {
if (currentLoop.length > 2) loops.push(currentLoop);
currentLoop = [];
}
}
currentLoop.push([p.x * scale, -p.y * scale]);
lastP = p;
}
if (currentLoop.length > 2) loops.push(currentLoop);
return loops;
};
export const convertFile = async (file, manifold, addLog) => {
if (!manifold) return null;
// CrossSection is a top-level export, NOT a static property of Manifold class
const { Manifold, CrossSection } = manifold;
const text = await file.text();
const parser = new DOMParser();
const doc = parser.parseFromString(text, "image/svg+xml");
const paths = {
black: [],
white: [],
cyan: []
};
// 1. Scale Calculation
let minX = Infinity, maxX = -Infinity;
const backgroundNodes = [];
const allPathNodes = Array.from(doc.querySelectorAll('path'));
allPathNodes.forEach(p => {
const cls = p.getAttribute('class');
if (!cls) backgroundNodes.push(p);
});
backgroundNodes.forEach(p => {
const d = p.getAttribute('d');
if (!d) return;
const pathEl = document.createElementNS("http://www.w3.org/2000/svg", "path");
pathEl.setAttribute("d", d);
const len = pathEl.getTotalLength();
for (let i = 0; i <= 10; i++) {
const pt = pathEl.getPointAtLength(i / 10 * len);
minX = Math.min(minX, pt.x);
maxX = Math.max(maxX, pt.x);
}
});
let scale = 1.0;
const TARGET_WIDTH = 87.80;
if (minX !== Infinity && maxX !== -Infinity) {
const currentWidth = maxX - minX;
if (currentWidth > 0) {
scale = TARGET_WIDTH / currentWidth;
addLog(` Scale factor: ${scale.toFixed(4)}`);
}
}
// 2. Process Paths with Classification
allPathNodes.forEach(p => {
const cls = p.getAttribute('class');
const d = p.getAttribute('d');
if (!d) return;
const loops = getPathPoints(d, scale);
if (cls === 'st2') paths.white.push(loops);
else if (cls === 'st1') paths.cyan.push(loops);
else paths.black.push(loops);
});
// 3. Extrusion Helper using Manifold
const createMeshBlob = (loopsList, height, z, isText = false) => {
const allContours = loopsList.flat();
if (allContours.length === 0) return null;
// Create CrossSection with Even-Odd rule
// Correct usage: new CrossSection(contours, fillRule)
let cs = new CrossSection(allContours, 'EvenOdd');
// Inset text for better adhesion (only for text layers)
if (isText) {
const INSET = -0.3; // mm
cs = cs.offset(INSET);
}
// Extrude
const mesh = Manifold.extrude(cs, height, 0, 0, [1, 1]);
// Translate Z
const meshZ = mesh.translate(0, 0, z);
// Convert to Mesh for Three.js export
const meshGL = new THREE.Mesh(getBufferGeometryFromManifold(meshZ, THREE));
const exporter = new STLExporter();
const stlString = exporter.parse(meshGL, { binary: true });
return new Blob([stlString], { type: 'application/octet-stream' });
};
// Constants
const BG_THICK = 3.0;
const TXT_THICK = 2.3; // 2.0 + 0.3mm inset compensation
const TXT_Z = 2.7; // Text is inset into background for better adhesion
return {
black: createMeshBlob(paths.black, BG_THICK, 0, false),
white: createMeshBlob(paths.white, TXT_THICK, TXT_Z, true),
cyan: createMeshBlob(paths.cyan, TXT_THICK, TXT_Z, true)
};
};
function getBufferGeometryFromManifold(manifoldMesh, THREE) {
const mesh = manifoldMesh.getMesh();
const geometry = new THREE.BufferGeometry();
const numVerts = mesh.vertProperties.length / mesh.numProp;
const vertices = new Float32Array(numVerts * 3);
for (let i = 0; i < numVerts; i++) {
vertices[i * 3] = mesh.vertProperties[i * mesh.numProp];
vertices[i * 3 + 1] = mesh.vertProperties[i * mesh.numProp + 1];
vertices[i * 3 + 2] = mesh.vertProperties[i * mesh.numProp + 2];
}
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
const indices = new Uint32Array(mesh.triVerts);
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
geometry.computeVertexNormals();
return geometry;
}

10
webapp/src/main.jsx Normal file
View File

@@ -0,0 +1,10 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>,
)

44
webapp/vite.config.js Normal file
View File

@@ -0,0 +1,44 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { VitePWA } from 'vite-plugin-pwa'
// https://vite.dev/config/
export default defineConfig({
plugins: [
react(),
VitePWA({
registerType: 'autoUpdate',
devOptions: {
enabled: true
},
includeAssets: ['favicon.ico', 'apple-touch-icon.png', 'mask-icon.svg', 'manifold.wasm'],
manifest: {
name: 'SVG Nametag Converter',
short_name: 'Nametag 3D',
description: 'Convert SVG files to 3D printable nametags offline.',
theme_color: '#1a1a1a',
background_color: '#1a1a1a',
display: 'standalone',
icons: [
{
src: 'pwa-192x192.png',
sizes: '192x192',
type: 'image/png'
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png'
}
]
},
workbox: {
globPatterns: ['**/*.{js,css,html,ico,png,svg,wasm}'],
maximumFileSizeToCacheInBytes: 41943040, // 40 MB, just to be safe for WASM
cleanupOutdatedCaches: true,
clientsClaim: true,
skipWaiting: true
}
})
],
})