Initial infrastructure documentation - comprehensive homelab reference
This commit is contained in:
15
Printing/.claude/index.html
Normal file
15
Printing/.claude/index.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Directory listing for /Printing/.claude/</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Directory listing for /Printing/.claude/</h1>
|
||||
<hr>
|
||||
<ul>
|
||||
<li><a href="settings.local.json">settings.local.json</a></li>
|
||||
</ul>
|
||||
<hr>
|
||||
</body>
|
||||
</html>
|
||||
27
Printing/.claude/settings.local.json
Normal file
27
Printing/.claude/settings.local.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(python generate_nameplates.py:*)",
|
||||
"Bash(git add:*)",
|
||||
"Bash(git init:*)",
|
||||
"Bash(git remote add:*)",
|
||||
"Bash(git fetch:*)",
|
||||
"Bash(git commit:*)",
|
||||
"Bash(git push:*)",
|
||||
"Bash(git ls-remote:*)",
|
||||
"Bash(done)",
|
||||
"Bash(git pull:*)",
|
||||
"Bash(python:*)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -D 'name=\"\"Fred\"\"' -o \"TEST_Fred_raised_text.stl\" \"zipper_pull_raised_text_template.scad\")",
|
||||
"Bash(ls:*)",
|
||||
"Bash(head:*)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" \"zipper-pulls-raised-text/Ford-Fred (2).stl\" --export-format echo --o -)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" \"zipper-pulls-raised-text/111.stl\" --export-format echo --o -)",
|
||||
"Bash(dir \"C:\\Users\\Fred\\.claude-worktrees\\Printing\\eager-bose\\Nameplates\\zipper-pulls-raised-text\" /T:W)",
|
||||
"Bash(findstr:*)",
|
||||
"Bash(powershell:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
}
|
||||
}
|
||||
41
Printing/.gitignore
vendored
Normal file
41
Printing/.gitignore
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
# Generated STL files
|
||||
*.stl
|
||||
|
||||
# Build artifacts
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Python cache
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
.Python
|
||||
*.so
|
||||
|
||||
# Virtual environments
|
||||
venv/
|
||||
env/
|
||||
ENV/
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
desktop.ini
|
||||
|
||||
# Node.js (if accidentally included)
|
||||
node_modules/
|
||||
*.tar.xz
|
||||
*.tar.gz
|
||||
|
||||
# Temporary files
|
||||
*~
|
||||
*.tmp
|
||||
*.temp
|
||||
test_output.stl
|
||||
453
Printing/CLAUDE.md
Normal file
453
Printing/CLAUDE.md
Normal file
@@ -0,0 +1,453 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
A collection of 3D printing utilities for generating personalized STL files using **Python + OpenSCAD**. The repository contains two main subprojects:
|
||||
|
||||
1. **Nameplates** - Batch nameplate and zipper pull generator
|
||||
2. **Key caps** - Mechanical keyboard keycap scaling utilities
|
||||
|
||||
All projects use OpenSCAD as the 3D modeling engine, invoked via Python scripts or standalone SCAD files.
|
||||
|
||||
## Repository Structure
|
||||
|
||||
```
|
||||
Printing/
|
||||
├── Nameplates/ # Nameplate and zipper pull generators
|
||||
│ ├── generate_nameplates.py # Batch nameplate generator
|
||||
│ ├── generate_zipper_pulls.py # Batch zipper pull generator
|
||||
│ ├── nameplate_template.scad # Nameplate template (38mm height, no hole)
|
||||
│ ├── zipper_pull_template.scad # Zipper pull template (34mm height, 4mm hole)
|
||||
│ ├── names.txt # Input names (one per line)
|
||||
│ ├── output_stl/ # Generated nameplate STLs
|
||||
│ ├── zipper-pulls/ # Generated zipper pull STLs
|
||||
│ ├── Fordscript.ttf # Custom cursive font (must be installed)
|
||||
│ └── CLAUDE.md # Detailed nameplate documentation
|
||||
│
|
||||
└── Key caps/ # Keyboard keycap scaling
|
||||
├── Body5_scaled_FIXED.scad # Primary keycap scaling script
|
||||
├── Body5.stl # Original keycap model
|
||||
├── CLAUDE.md # Detailed keycap documentation
|
||||
└── README_scaling.md # User guide for scaling workflow
|
||||
```
|
||||
|
||||
## Critical Dependencies
|
||||
|
||||
### OpenSCAD Installation
|
||||
- **Path**: `C:\Program Files\OpenSCAD\openscad.exe` (hardcoded in Python scripts)
|
||||
- **Download**: https://openscad.org/downloads.html
|
||||
- **Update path** in scripts if installed elsewhere (see `generate_nameplates.py:36`, `generate_zipper_pulls.py:36`)
|
||||
|
||||
### Font Requirements (Nameplates/Zipper Pulls Only)
|
||||
- **Font**: Fordscript cursive font (`Nameplates/Fordscript.ttf`)
|
||||
- **Installation**: Must be installed in Windows (right-click → Install for all users)
|
||||
- **Critical**: OpenSCAD references fonts by system name, not file path
|
||||
- **Verification**: After install, restart OpenSCAD before generating files
|
||||
|
||||
## Key Commands
|
||||
|
||||
### Nameplates
|
||||
```bash
|
||||
# Generate all nameplates (38mm height, no hole)
|
||||
cd Nameplates
|
||||
python generate_nameplates.py
|
||||
|
||||
# Output: output_stl/*.stl
|
||||
```
|
||||
|
||||
### Zipper Pulls
|
||||
```bash
|
||||
# Generate all zipper pulls (100mm × 34mm total, 4mm hole with 1mm clearance)
|
||||
cd Nameplates
|
||||
python generate_zipper_pulls.py
|
||||
|
||||
# Output: zipper-pulls/*.stl
|
||||
```
|
||||
|
||||
### Key Caps
|
||||
```powershell
|
||||
# Render scaled keycap (command line)
|
||||
& "C:\Program Files\OpenSCAD\openscad.exe" -o "output.stl" "Body5_scaled_FIXED.scad"
|
||||
|
||||
# Or: Open in OpenSCAD GUI, adjust parameters, press F6 to render, export STL
|
||||
& "C:\Program Files\OpenSCAD\openscad.exe" "Body5_scaled_FIXED.scad"
|
||||
```
|
||||
|
||||
### Manual OpenSCAD Testing
|
||||
```powershell
|
||||
# Test single nameplate
|
||||
& "C:\Program Files\OpenSCAD\openscad.exe" -D 'name="TestName"' -o test_output.stl nameplate_template.scad
|
||||
|
||||
# Test single zipper pull
|
||||
& "C:\Program Files\OpenSCAD\openscad.exe" -D 'name="TestName"' -o test_output.stl zipper_pull_template.scad
|
||||
|
||||
# Preview in GUI (edit parameters at top of file)
|
||||
& "C:\Program Files\OpenSCAD\openscad.exe" nameplate_template.scad
|
||||
```
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Nameplates vs Zipper Pulls
|
||||
|
||||
Both use the same two-layer oval design (white base + blue top with engraved text) but differ in dimensions and features:
|
||||
|
||||
| Feature | Nameplates | Zipper Pulls |
|
||||
|---------|-----------|-------------|
|
||||
| Template | `nameplate_template.scad` | `zipper_pull_template.scad` |
|
||||
| Generator | `generate_nameplates.py` | `generate_zipper_pulls.py` |
|
||||
| Total Size (W×H) | 100mm × 38mm | 100mm × 34mm |
|
||||
| Blue Layer Size | 96mm × 34mm | 96mm × 30mm |
|
||||
| White Base Offset | 2mm all sides | 2mm all sides |
|
||||
| Font Size | 30mm | 13mm |
|
||||
| Hole | None | 4mm diameter, left side |
|
||||
| Hole Clearance | N/A | 1mm from white base edge |
|
||||
| Output Directory | `output_stl/` | `zipper-pulls/` |
|
||||
| Use Case | Display nameplates | Zipper/bag attachments |
|
||||
|
||||
**Important**: These are separate templates and scripts. Modifying one does not affect the other.
|
||||
|
||||
### Pipeline Architecture
|
||||
|
||||
```
|
||||
names.txt
|
||||
↓
|
||||
Python Generator Script (reads names, iterates)
|
||||
↓
|
||||
OpenSCAD CLI (renders each name via template)
|
||||
↓
|
||||
STL Files (output to respective directories)
|
||||
```
|
||||
|
||||
**Key Pattern**: Python script calls OpenSCAD subprocess for each name:
|
||||
```python
|
||||
cmd = [
|
||||
r'C:\Program Files\OpenSCAD\openscad.exe',
|
||||
'-D', f'name="{escaped_name}"', # Override parameter
|
||||
'-o', output_file, # Output STL path
|
||||
template_file # SCAD template
|
||||
]
|
||||
subprocess.run(cmd, capture_output=True, text=True, check=True)
|
||||
```
|
||||
|
||||
### OpenSCAD Template Pattern
|
||||
|
||||
All SCAD templates follow this structure:
|
||||
```scad
|
||||
// 1. Parameters (overridable via -D flag)
|
||||
name = "NAME";
|
||||
oval_width = 100;
|
||||
// ... more parameters
|
||||
|
||||
// 2. Modules (reusable geometry functions)
|
||||
module oval(width, height, depth) { ... }
|
||||
module base_layer() { ... }
|
||||
module top_layer() { ... }
|
||||
|
||||
// 3. Assembly module
|
||||
module nameplate() {
|
||||
base_layer();
|
||||
top_layer();
|
||||
}
|
||||
|
||||
// 4. Execution (builds the model)
|
||||
nameplate();
|
||||
```
|
||||
|
||||
## Project-Specific Conventions
|
||||
|
||||
### Name Sanitization
|
||||
Python scripts convert names to safe filenames:
|
||||
- Removes special characters (keeps alphanumeric, spaces, hyphens, underscores)
|
||||
- Replaces spaces with underscores
|
||||
- Escapes quotes for shell: `name.replace('"', '\\"')`
|
||||
- Example: `"John Doe"` → `John_Doe.stl`
|
||||
|
||||
### Two-Layer Design Philosophy
|
||||
- **White base layer**: Structural foundation, extends beyond blue layer by `base_offset` (2mm)
|
||||
- **Blue top layer**: Visual layer with engraved text
|
||||
- **Text engraving**: Cuts completely through blue layer (`text_depth = top_thickness = 1mm`) to expose white base underneath
|
||||
- **Result**: White text on blue background
|
||||
|
||||
### Hole Positioning (Zipper Pulls)
|
||||
Hole is positioned on left side with clearance from white base edge:
|
||||
```scad
|
||||
white_width = oval_width + base_offset*2;
|
||||
hole_x = -(white_width/2) + (hole_diameter/2) + hole_clearance;
|
||||
// For 96mm blue + 2mm offset = 100mm white, 4mm hole, 1mm clearance:
|
||||
// hole_x = -50 + 2 + 1 = -47mm from center
|
||||
```
|
||||
|
||||
**Critical**:
|
||||
- `hole_clearance` must be sufficient to prevent hole from breaking through oval edge. Current value (1mm) tested and verified.
|
||||
- Hole is positioned relative to **white base width**, not blue layer width, to ensure it stays within the white outline.
|
||||
|
||||
## Common Workflows
|
||||
|
||||
### Add New Names to Both Systems
|
||||
1. Edit `Nameplates/names.txt`, add name on new line
|
||||
2. Run both generators:
|
||||
```bash
|
||||
cd Nameplates
|
||||
python generate_nameplates.py # Creates nameplate
|
||||
python generate_zipper_pulls.py # Creates zipper pull
|
||||
```
|
||||
3. Find STLs in `output_stl/` and `zipper-pulls/` respectively
|
||||
|
||||
### Adjust Zipper Pull Hole Clearance
|
||||
If hole is too close to edge or breaking through:
|
||||
1. Edit `zipper_pull_template.scad`, line 17:
|
||||
```scad
|
||||
hole_clearance = 1; // Increase this value
|
||||
```
|
||||
2. Regenerate all zipper pulls:
|
||||
```bash
|
||||
python generate_zipper_pulls.py
|
||||
```
|
||||
|
||||
**Note**: Hole clearance is measured from the **white base edge**, not the blue layer edge.
|
||||
|
||||
### Create Custom Dimension Variant
|
||||
To create a new variant (e.g., smaller nameplates):
|
||||
1. Copy existing template: `nameplate_template.scad` → `nameplate_small_template.scad`
|
||||
2. Modify dimensions at top of new file
|
||||
3. Copy generator script: `generate_nameplates.py` → `generate_nameplates_small.py`
|
||||
4. Update generator to use new template and output directory:
|
||||
```python
|
||||
template_file = "nameplate_small_template.scad"
|
||||
output_dir = "output_stl_small"
|
||||
```
|
||||
|
||||
### Scale Keycaps for Different Tolerances
|
||||
1. Open `Key caps/Body5_scaled_FIXED.scad` in OpenSCAD GUI
|
||||
2. Adjust `body_scale_xy` parameter at top (default: 0.98 = 98%)
|
||||
- Too tight: decrease to 0.97 (3% reduction)
|
||||
- Too loose: increase to 0.99 (1% reduction)
|
||||
3. Press `F5` for preview, `F6` for full render
|
||||
4. Export via `File > Export > Export as STL`
|
||||
5. Test print and iterate
|
||||
|
||||
See `Key caps/README_scaling.md` for detailed keycap scaling workflow.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Font Not Found (Nameplates/Zipper Pulls)
|
||||
**Symptom**: Text is missing or uses default font in generated STLs.
|
||||
|
||||
**Fix**:
|
||||
1. Install `Fordscript.ttf`: Right-click → "Install for all users"
|
||||
2. Restart OpenSCAD if running
|
||||
3. Test with manual command:
|
||||
```powershell
|
||||
& "C:\Program Files\OpenSCAD\openscad.exe" -D 'name="Test"' -o test.stl nameplate_template.scad
|
||||
```
|
||||
4. Open `test.stl` in slicer and verify text appears
|
||||
|
||||
### OpenSCAD Path Not Found
|
||||
**Symptom**: `FileNotFoundError: OpenSCAD not found`
|
||||
|
||||
**Fix**: Update hardcoded path in generator scripts:
|
||||
```python
|
||||
# In generate_nameplates.py and generate_zipper_pulls.py, line 36:
|
||||
cmd = [
|
||||
r'C:\Program Files\OpenSCAD\openscad.exe', # ← Update this path
|
||||
# ...
|
||||
]
|
||||
```
|
||||
|
||||
### Zipper Pull Hole Breaking Through Edge
|
||||
**Symptom**: Hole intersects with oval edge, causing weak point or break.
|
||||
|
||||
**Fix**: Increase `hole_clearance` in `zipper_pull_template.scad`:
|
||||
```scad
|
||||
hole_clearance = 1.5; // Increase from 1mm to 1.5mm
|
||||
```
|
||||
Then regenerate all zipper pulls.
|
||||
|
||||
**Note**: Ensure hole clearance is measured from the white base edge (100mm total width), not the blue layer edge (96mm).
|
||||
|
||||
### Keycap Stem Scaled Incorrectly
|
||||
**Symptom**: Cherry MX stem doesn't fit switch after scaling.
|
||||
|
||||
**Cause**: Using wrong SCAD file (non-FIXED version requires manual stem positioning).
|
||||
|
||||
**Fix**: Always use `Body5_scaled_FIXED.scad` which uses centered import approach. The stem preservation region is automatically centered at origin.
|
||||
|
||||
## Advanced Customization
|
||||
|
||||
### Add Custom Parameter to Templates
|
||||
To add a new parameter (e.g., border thickness):
|
||||
|
||||
1. Add parameter to template:
|
||||
```scad
|
||||
border_thickness = 0.5; // New parameter
|
||||
```
|
||||
|
||||
2. Use in geometry:
|
||||
```scad
|
||||
module base_layer() {
|
||||
difference() {
|
||||
oval(oval_width, oval_height, base_thickness);
|
||||
// Cut border groove
|
||||
translate([0, 0, base_thickness - border_thickness])
|
||||
oval(oval_width - 4, oval_height - 4, border_thickness + 0.1);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Pass from Python script (optional):
|
||||
```python
|
||||
cmd = [
|
||||
r'C:\Program Files\OpenSCAD\openscad.exe',
|
||||
'-D', f'name="{escaped_name}"',
|
||||
'-D', f'border_thickness={thickness}', # Override parameter
|
||||
'-o', output_file,
|
||||
template_file
|
||||
]
|
||||
```
|
||||
|
||||
### Batch Generate Multiple Sizes
|
||||
Modify generator script to loop over multiple configurations:
|
||||
|
||||
```python
|
||||
configs = [
|
||||
{"template": "nameplate_template.scad", "width": 100, "height": 38},
|
||||
{"template": "nameplate_template.scad", "width": 80, "height": 30},
|
||||
{"template": "nameplate_template.scad", "width": 60, "height": 23},
|
||||
]
|
||||
|
||||
for name in names:
|
||||
for config in configs:
|
||||
output_file = f"{config['width']}x{config['height']}_{safe_name}.stl"
|
||||
cmd = [
|
||||
r'C:\Program Files\OpenSCAD\openscad.exe',
|
||||
'-D', f'name="{escaped_name}"',
|
||||
'-D', f'oval_width={config["width"]}',
|
||||
'-D', f'oval_height={config["height"]}',
|
||||
'-o', output_file,
|
||||
config["template"]
|
||||
]
|
||||
subprocess.run(cmd, ...)
|
||||
```
|
||||
|
||||
## Development Reference
|
||||
|
||||
### OpenSCAD Command Line Flags
|
||||
```powershell
|
||||
# Override parameter
|
||||
-D 'name="value"'
|
||||
|
||||
# Output file
|
||||
-o output.stl
|
||||
|
||||
# Check syntax (no output)
|
||||
--check
|
||||
|
||||
# Verbose output
|
||||
--verbose
|
||||
|
||||
# Clear cache (useful when changing imports)
|
||||
--clear-cache
|
||||
|
||||
# Version info
|
||||
--version
|
||||
```
|
||||
|
||||
### Python Subprocess Pattern
|
||||
All generators use the same pattern:
|
||||
```python
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True, # Capture stdout/stderr
|
||||
text=True, # Return strings, not bytes
|
||||
check=True # Raise CalledProcessError on non-zero exit
|
||||
)
|
||||
```
|
||||
|
||||
Error handling:
|
||||
```python
|
||||
try:
|
||||
subprocess.run(cmd, capture_output=True, text=True, check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error: {e.stderr}")
|
||||
except FileNotFoundError:
|
||||
print("OpenSCAD not found. Install from https://openscad.org")
|
||||
```
|
||||
|
||||
## File Organization Guidelines
|
||||
|
||||
### When to Create New Template vs Modify Existing
|
||||
|
||||
**Create New Template** if:
|
||||
- Fundamentally different design (e.g., adding holes, changing shape)
|
||||
- Different use case (nameplates vs zipper pulls)
|
||||
- Need to maintain both versions simultaneously
|
||||
|
||||
**Modify Existing Template** if:
|
||||
- Adjusting dimensions only
|
||||
- Tweaking existing features
|
||||
- Single-use or temporary change
|
||||
|
||||
### Output Directory Naming
|
||||
- Use descriptive names: `output_stl/`, `zipper-pulls/`
|
||||
- Keep separate output directories for different variants
|
||||
- Never mix different variants in the same directory (prevents confusion)
|
||||
|
||||
### Generator Script Naming
|
||||
- Match template name: `generate_nameplates.py` uses `nameplate_template.scad`
|
||||
- Be explicit: `generate_zipper_pulls.py` not `generate_zippers.py`
|
||||
- One template per generator for clarity
|
||||
|
||||
## 3D Printing Notes
|
||||
|
||||
### Recommended Slicer Settings
|
||||
- **Material**: Two colors (white + blue PLA recommended)
|
||||
- **Layer Height**: 0.1-0.2mm for clean text details
|
||||
- **Infill**: 20-30% (thin parts don't need much)
|
||||
- **Supports**: Not needed (flat design, print as modeled)
|
||||
- **Orientation**: Print flat on bed
|
||||
- **Bed Adhesion**: Brim or raft recommended for thin parts
|
||||
- **First Layer**: Critical for thin 1.5mm base - ensure good adhesion
|
||||
|
||||
### Multi-Color Printing
|
||||
Two approaches:
|
||||
1. **Filament swap**: Print white base, pause, swap to blue, continue
|
||||
2. **Two prints**: Print white base separately, print blue top, glue together
|
||||
|
||||
**Important**: Text must be fully engraved through blue layer to show white underneath.
|
||||
|
||||
#### M600 Filament Change Height
|
||||
When using M600 command for automatic filament change in slicer:
|
||||
- **Base layer thickness**: 1.5mm
|
||||
- **Actual M600 height**: 1.5mm + one layer height
|
||||
- **Reason**: M600 triggers BEFORE the specified layer is printed. If set to exactly 1.5mm, the slicer will print one solid white layer at 1.5mm, then trigger M600, then start the blue outline and text.
|
||||
- **Example**: With 0.2mm layer height, set M600 at 1.7mm (1.5 + 0.2) to ensure filament change happens at the correct layer.
|
||||
- **Verification**: After slicing, verify that the layer immediately after M600 begins the blue top layer, not another white layer.
|
||||
|
||||
## Project-Specific Quirks
|
||||
|
||||
### Why Two Separate Templates for Nameplates/Zipper Pulls?
|
||||
- Different dimensions (38mm vs 34mm height)
|
||||
- Zipper pulls need hole, nameplates don't
|
||||
- Maintains backward compatibility with existing nameplate output
|
||||
- Allows independent evolution of each variant
|
||||
|
||||
### Why Hardcoded OpenSCAD Path?
|
||||
- Windows standard installation location is consistent
|
||||
- Avoids PATH environment complexity
|
||||
- Easy to update in one place per script
|
||||
- Future: Consider environment variable or config file
|
||||
|
||||
### Why Manual Font Installation?
|
||||
- OpenSCAD uses system font registry, not file paths
|
||||
- Ensures consistent font rendering across machines
|
||||
- Font must be available to OpenSCAD process
|
||||
- No programmatic workaround exists
|
||||
|
||||
### Keycap Stem Preservation Algorithm
|
||||
- Circular region around stem preserved at 100% scale
|
||||
- Rest of keycap scaled down for better fit
|
||||
- Cherry MX stem is exactly 4mm × 4mm by spec (must not scale)
|
||||
- Circular preservation accommodates off-brand switch tolerances
|
||||
- See `Key caps/CLAUDE.md` for detailed algorithm explanation
|
||||
1
Printing/Key caps/.claude/commands
Normal file
1
Printing/Key caps/.claude/commands
Normal file
@@ -0,0 +1 @@
|
||||
C:/Users/Fred/claude-shared/commands
|
||||
16
Printing/Key caps/.claude/index.html
Normal file
16
Printing/Key caps/.claude/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Directory listing for /Printing/Key caps/.claude/</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Directory listing for /Printing/Key caps/.claude/</h1>
|
||||
<hr>
|
||||
<ul>
|
||||
<li><a href="commands">commands</a></li>
|
||||
<li><a href="settings.local.json">settings.local.json</a></li>
|
||||
</ul>
|
||||
<hr>
|
||||
</body>
|
||||
</html>
|
||||
23
Printing/Key caps/.claude/settings.local.json
Normal file
23
Printing/Key caps/.claude/settings.local.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(where:*)",
|
||||
"Bash(if exist \"C:\\Program Files\\OpenSCAD\\openscad.exe\" echo Found at C:Program FilesOpenSCADopenscad.exe)",
|
||||
"Bash(\"/c/Program Files/OpenSCAD/openscad.exe\" -o \"Body5_scaled_98percent.stl\" \"Body5_scaled.scad\")",
|
||||
"Bash(\"/c/Program Files/OpenSCAD/openscad.exe\" --clear-cache -o \"Body5_scaled_98percent.stl\" \"Body5_scaled.scad\")",
|
||||
"Bash(\"/c/Program Files/OpenSCAD/openscad.exe\" -o \"Body5_TEST_circle.stl\" \"Body5_test_circle.scad\")",
|
||||
"Bash(\"/c/Program Files/OpenSCAD/openscad.exe\" -o \"test_cylinder.stl\" \"test_cylinder.scad\")",
|
||||
"Bash(\"/c/Program Files/OpenSCAD/openscad.exe\" -o \"Body5_scaled_FIXED_98percent.stl\" \"Body5_scaled_FIXED.scad\")",
|
||||
"Bash(\"/c/Program Files/OpenSCAD/openscad.exe\" --clear-cache -o \"Body5(1)_scaled_98percent.stl\" \"Body5(1)_scaled.scad\")",
|
||||
"Bash(\"/c/Program Files/OpenSCAD/openscad.exe\" -o \"Body5(1)_scaled_98percent.stl\" \"Body5(1)_scaled.scad\")",
|
||||
"Bash(ls:*)",
|
||||
"Bash(\"/c/Program Files/OpenSCAD/openscad.exe\" -D number_to_generate=1 -o \"Body5_num1.stl\" \"generate_numbered_keycaps.scad\")",
|
||||
"Bash(cmd /c generate_all_numbered_keycaps.bat)",
|
||||
"Bash(for i in {2..20})",
|
||||
"Bash(do \"/c/Program Files/OpenSCAD/openscad.exe\" -D number_to_generate=$i -o \"Body5_num$i.stl\" \"generate_numbered_keycaps.scad\")",
|
||||
"Bash(done)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
}
|
||||
}
|
||||
55
Printing/Key caps/Body5(1)_scaled.scad
Normal file
55
Printing/Key caps/Body5(1)_scaled.scad
Normal file
@@ -0,0 +1,55 @@
|
||||
// =====================================================
|
||||
// Keycap Body Scaling Script - FIXED VERSION
|
||||
// =====================================================
|
||||
// This script scales down the keycap body while preserving
|
||||
// the Cherry MX stem at its original 4mm x 4mm dimensions
|
||||
//
|
||||
// FIX: Centers the model first so cylinder operations work correctly
|
||||
// =====================================================
|
||||
|
||||
// ----- ADJUSTABLE PARAMETERS -----
|
||||
|
||||
body_scale_xy = 0.98; // 98% of original (2% smaller)
|
||||
body_scale_z = 1.00; // Keep height at 100%
|
||||
|
||||
stem_diameter = 4.8; // Diameter of circular stem preservation region (4.8mm to preserve 4mm x 4mm cross)
|
||||
stem_height = 10.0; // Height of stem region to preserve (tall enough to capture entire stem)
|
||||
stem_z_offset = -1.0; // Z offset to position cylinder on the stem
|
||||
$fn = 128; // Circle smoothness
|
||||
|
||||
stl_filename = "Body5(1).stl";
|
||||
|
||||
// =====================================================
|
||||
// MAIN MODEL - CENTERED APPROACH
|
||||
// =====================================================
|
||||
|
||||
// Center the imported model at origin
|
||||
// The stem cross should be centered at X=209, Y=223.5 in the original STL
|
||||
module centered_import() {
|
||||
translate([-209, -223.5, 0]) // Center X and Y on the stem
|
||||
import(stl_filename);
|
||||
}
|
||||
|
||||
union() {
|
||||
// Part 1: Scaled body WITHOUT the circular stem region
|
||||
difference() {
|
||||
scale([body_scale_xy, body_scale_xy, body_scale_z]) {
|
||||
centered_import();
|
||||
}
|
||||
|
||||
// Cut out a cylinder where the stem is
|
||||
translate([0, 0, stem_z_offset]) {
|
||||
cylinder(h = stem_height, d = stem_diameter + 0.5, center = true);
|
||||
}
|
||||
}
|
||||
|
||||
// Part 2: Original UNSCALED stem region (circular)
|
||||
intersection() {
|
||||
centered_import(); // NOT scaled - preserves original 4mm x 4mm cross
|
||||
|
||||
// Cylinder defines the 4.8mm circular stem region to keep at 100% scale
|
||||
translate([0, 0, stem_z_offset]) {
|
||||
cylinder(h = stem_height, d = stem_diameter, center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
98
Printing/Key caps/Body5_scaled.scad
Normal file
98
Printing/Key caps/Body5_scaled.scad
Normal file
@@ -0,0 +1,98 @@
|
||||
// =====================================================
|
||||
// Keycap Body Scaling Script
|
||||
// =====================================================
|
||||
// This script scales down the keycap body while preserving
|
||||
// the Cherry MX stem at its original 4mm x 4mm dimensions
|
||||
// within a CIRCULAR region (for off-brand switches)
|
||||
//
|
||||
// Usage:
|
||||
// 1. Adjust body_scale_xy below (start with 0.98 = 98%)
|
||||
// 2. Adjust stem_x and stem_y to position circle on the cross
|
||||
// 3. Press F5 to preview, F6 to render
|
||||
// 4. Export STL: File > Export > Export as STL
|
||||
// =====================================================
|
||||
|
||||
// ----- ADJUSTABLE PARAMETERS -----
|
||||
|
||||
// Body scaling factor for X and Y axes
|
||||
body_scale_xy = 0.98; // 98% of original (2% smaller)
|
||||
body_scale_z = 1.00; // Keep height at 100%
|
||||
|
||||
// ----- STEM DIMENSIONS -----
|
||||
// Position the circular preservation region on the stem cross
|
||||
|
||||
stem_x = 209; // X position of stem center (adjust to align with cross)
|
||||
stem_y = 223.5; // Y position of stem center (adjust to align with cross)
|
||||
stem_z = 3.85; // Z position of stem center (adjust if needed)
|
||||
|
||||
stem_diameter = 5.5; // Diameter of circular region around the stem
|
||||
stem_height = 8.0; // Height of stem region to preserve
|
||||
|
||||
$fn = 128; // Circle smoothness (128 = very smooth, 64 = balanced)
|
||||
|
||||
stl_filename = "Body5.stl";
|
||||
|
||||
// =====================================================
|
||||
// MAIN MODEL
|
||||
// =====================================================
|
||||
|
||||
union() {
|
||||
// Part 1: Scaled body WITHOUT the circular stem region
|
||||
difference() {
|
||||
// The scaled keycap body (scaled around origin, then positioned)
|
||||
translate([stem_x * (1 - body_scale_xy), stem_y * (1 - body_scale_xy), 0]) {
|
||||
scale([body_scale_xy, body_scale_xy, body_scale_z]) {
|
||||
import(stl_filename);
|
||||
}
|
||||
}
|
||||
|
||||
// Cut out a cylinder where the stem is
|
||||
translate([stem_x, stem_y, stem_z]) {
|
||||
cylinder(
|
||||
h = stem_height,
|
||||
d = stem_diameter + 0.5,
|
||||
center = true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Part 2: Original stem at 100% scale in CIRCULAR region
|
||||
intersection() {
|
||||
// The original unscaled model
|
||||
import(stl_filename);
|
||||
|
||||
// A cylinder that defines the CIRCULAR stem region to keep
|
||||
translate([stem_x, stem_y, stem_z]) {
|
||||
cylinder(
|
||||
h = stem_height,
|
||||
d = stem_diameter,
|
||||
center = true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// NOTES
|
||||
// =====================================================
|
||||
//
|
||||
// ADJUSTING THE CIRCULAR REGION POSITION:
|
||||
// If the circle is not centered on the cross stem:
|
||||
// 1. Open in OpenSCAD and press F5 to preview
|
||||
// 2. Rotate the view to see the stem from below
|
||||
// 3. Adjust stem_x and stem_y values until circle is centered on cross
|
||||
// 4. Typical adjustment: try values between 208-210 for X, 222-225 for Y
|
||||
//
|
||||
// ITERATIVE TESTING WORKFLOW:
|
||||
// 1. Start with body_scale_xy = 0.98 (98%)
|
||||
// 2. Export STL and test print
|
||||
// 3. If keycap is still too tight, decrease to 0.97
|
||||
// 4. If keycap is too loose, increase to 0.99
|
||||
// 5. Fine-tune in 0.005 increments (e.g., 0.975, 0.985)
|
||||
//
|
||||
// STEM DIAMETER ADJUSTMENT:
|
||||
// - Increase stem_diameter if you need more clearance around the cross
|
||||
// - Decrease stem_diameter for tighter tolerance
|
||||
// - Typical range: 4.5mm to 6.0mm
|
||||
//
|
||||
// =====================================================
|
||||
53
Printing/Key caps/Body5_scaled_FIXED.scad
Normal file
53
Printing/Key caps/Body5_scaled_FIXED.scad
Normal file
@@ -0,0 +1,53 @@
|
||||
// =====================================================
|
||||
// Keycap Body Scaling Script - FIXED VERSION
|
||||
// =====================================================
|
||||
// This script scales down the keycap body while preserving
|
||||
// the Cherry MX stem at its original 4mm x 4mm dimensions
|
||||
//
|
||||
// FIX: Centers the model first so cylinder operations work correctly
|
||||
// =====================================================
|
||||
|
||||
// ----- ADJUSTABLE PARAMETERS -----
|
||||
|
||||
body_scale_xy = 0.98; // 98% of original (2% smaller)
|
||||
body_scale_z = 1.00; // Keep height at 100%
|
||||
|
||||
stem_diameter = 5.5; // Diameter of circular stem preservation region
|
||||
stem_height = 8.0; // Height of stem region to preserve
|
||||
$fn = 128; // Circle smoothness
|
||||
|
||||
stl_filename = "Body5.stl";
|
||||
|
||||
// =====================================================
|
||||
// MAIN MODEL - CENTERED APPROACH
|
||||
// =====================================================
|
||||
|
||||
// First, we need to center the imported model
|
||||
// The original STL is positioned around x≈209, y≈220
|
||||
// We'll measure the bounding box and center it
|
||||
|
||||
module centered_import() {
|
||||
// Import and center the model at origin
|
||||
translate([-209, -223.5, -4.9]) // Approximate center based on STL coordinates
|
||||
import(stl_filename);
|
||||
}
|
||||
|
||||
union() {
|
||||
// Part 1: Scaled body WITHOUT the circular stem region
|
||||
difference() {
|
||||
scale([body_scale_xy, body_scale_xy, body_scale_z]) {
|
||||
centered_import();
|
||||
}
|
||||
|
||||
// Cut out a cylinder where the stem is (now centered at origin)
|
||||
cylinder(h = stem_height, d = stem_diameter + 0.5, center = true);
|
||||
}
|
||||
|
||||
// Part 2: Original unscaled stem region (circular)
|
||||
intersection() {
|
||||
centered_import();
|
||||
|
||||
// Cylinder defines the circular stem region to keep
|
||||
cylinder(h = stem_height, d = stem_diameter, center = true);
|
||||
}
|
||||
}
|
||||
31
Printing/Key caps/Body5_test_circle.scad
Normal file
31
Printing/Key caps/Body5_test_circle.scad
Normal file
@@ -0,0 +1,31 @@
|
||||
// TEST VERSION - Exaggerated circular cutout to verify it's working
|
||||
|
||||
body_scale_xy = 0.98;
|
||||
body_scale_z = 1.00;
|
||||
|
||||
stem_diameter = 8.0; // MUCH larger to make the circle obvious
|
||||
stem_height = 10.0; // Taller to ensure we capture everything
|
||||
stem_z_position = 0;
|
||||
$fn = 128;
|
||||
|
||||
stl_filename = "Body5.stl";
|
||||
|
||||
union() {
|
||||
difference() {
|
||||
scale([body_scale_xy, body_scale_xy, body_scale_z]) {
|
||||
import(stl_filename);
|
||||
}
|
||||
// Large obvious cylinder
|
||||
translate([0, 0, stem_z_position]) {
|
||||
cylinder(h = 20, d = stem_diameter + 0.5, center = true);
|
||||
}
|
||||
}
|
||||
|
||||
intersection() {
|
||||
import(stl_filename);
|
||||
// Large obvious cylinder
|
||||
translate([0, 0, stem_z_position]) {
|
||||
cylinder(h = 20, d = stem_diameter, center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
80
Printing/Key caps/CLAUDE.md
Normal file
80
Printing/Key caps/CLAUDE.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
This is an OpenSCAD project for scaling 3D-printed mechanical keyboard keycaps while preserving the Cherry MX stem dimensions. The project contains scripts to reduce keycap body dimensions for better socket fit while maintaining the exact 4mm × 4mm stem cross dimensions required for Cherry MX switches.
|
||||
|
||||
## Key Commands
|
||||
|
||||
### Rendering STL Files
|
||||
|
||||
On Windows, OpenSCAD is typically installed at `C:\Program Files\OpenSCAD\openscad.exe`. Use Git Bash path format:
|
||||
|
||||
```bash
|
||||
# Render a SCAD file to STL
|
||||
"/c/Program Files/OpenSCAD/openscad.exe" -o "output.stl" "input.scad"
|
||||
|
||||
# Clear cache and render (recommended when changing imports)
|
||||
"/c/Program Files/OpenSCAD/openscad.exe" --clear-cache -o "output.stl" "input.scad"
|
||||
```
|
||||
|
||||
### Verify OpenSCAD Installation
|
||||
|
||||
```bash
|
||||
# Check if OpenSCAD is installed
|
||||
if exist "C:\Program Files\OpenSCAD\openscad.exe" echo Found at C:\Program Files\OpenSCAD\openscad.exe
|
||||
```
|
||||
|
||||
## Project Architecture
|
||||
|
||||
### Main Scripts
|
||||
|
||||
- **`Body5_scaled_FIXED.scad`**: The primary working script that uses a centered-import approach. This is the recommended version for scaling keycaps.
|
||||
- **`Body5_scaled.scad`**: Earlier version that manually positions the stem preservation cylinder using explicit X/Y coordinates.
|
||||
- **`Body5_test_circle.scad`**: Test script with exaggerated parameters (larger cylinder) to verify the circular stem preservation is working.
|
||||
- **`test_cylinder.scad`**: Simple cylinder rendering test for OpenSCAD verification.
|
||||
|
||||
### STL Files
|
||||
|
||||
- **`Body5.stl`**: The original keycap model that gets imported and processed by the SCAD scripts.
|
||||
- **`Body2.stl`**: Alternative keycap model.
|
||||
- **Generated STL files**: Output from rendering the SCAD scripts (e.g., `Body5_scaled_98percent.stl`).
|
||||
|
||||
### Scaling Algorithm
|
||||
|
||||
The scripts use a two-part union approach:
|
||||
|
||||
1. **Scaled Body with Cutout**: The entire keycap is scaled down by `body_scale_xy`, then a cylinder is subtracted where the stem should be
|
||||
2. **Unscaled Stem Region**: A cylinder intersection preserves the original stem region at 100% scale
|
||||
3. **Union**: Both parts are merged, creating a keycap with scaled body but original stem dimensions
|
||||
|
||||
The `_FIXED` version centers the model at the origin before operations, making cylinder placement simpler. The non-FIXED version requires manual positioning of the preservation cylinder using `stem_x` and `stem_y` coordinates.
|
||||
|
||||
### Critical Parameters
|
||||
|
||||
- **`body_scale_xy`**: X/Y scaling factor (typically 0.97-0.99 for 1-3% reduction)
|
||||
- **`body_scale_z`**: Z scaling factor (keep at 1.00 to maintain keycap height)
|
||||
- **`stem_diameter`**: Diameter of circular preservation region (default: 5.5mm)
|
||||
- **`stem_height`**: Height of stem region (default: 8.0mm)
|
||||
- **`$fn`**: OpenSCAD circle resolution (64-128, higher = smoother but slower)
|
||||
|
||||
### Centering Approach (FIXED version)
|
||||
|
||||
The `centered_import()` module translates the imported STL by `[-209, -223.5, -4.9]` to center it at the origin. These values were determined by analyzing the original STL's bounding box. This allows stem operations to use simple `cylinder()` calls at the origin rather than calculating offsets.
|
||||
|
||||
## Development Workflow
|
||||
|
||||
1. Modify SCAD script parameters (typically just `body_scale_xy`)
|
||||
2. Render to STL using OpenSCAD command line or GUI (F5 preview, F6 full render in GUI)
|
||||
3. Import STL into slicer and print test keycap
|
||||
4. Measure fit and iterate on scaling factor
|
||||
5. Typical iteration: start at 0.98, adjust by 0.01 increments based on fit testing
|
||||
|
||||
## Important Notes
|
||||
|
||||
- The Cherry MX stem cross is exactly 4mm × 4mm by specification and must not be scaled
|
||||
- The circular preservation region accommodates off-brand switches that may have slightly different tolerances
|
||||
- All SCAD scripts expect `Body5.stl` (or specified STL file) to be in the same directory
|
||||
- Rendering is computationally intensive due to importing the STL twice (once for scaling, once for stem preservation)
|
||||
109
Printing/Key caps/README_scaling.md
Normal file
109
Printing/Key caps/README_scaling.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# Keycap Scaling Guide
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. **Open the script**: Open `Body5_scaled.scad` in OpenSCAD
|
||||
2. **Adjust scaling**: Edit the `body_scale_xy` parameter at the top (default: 0.98 = 98%)
|
||||
3. **Preview**: Press `F5` to see a quick preview
|
||||
4. **Render**: Press `F6` to fully render (required before export)
|
||||
5. **Export**: Go to `File > Export > Export as STL`
|
||||
6. **Test print**: Print and check the fit
|
||||
7. **Iterate**: Adjust the scale parameter and repeat if needed
|
||||
|
||||
## Key Parameters
|
||||
|
||||
### `body_scale_xy`
|
||||
- **Default**: `0.98` (98% of original size)
|
||||
- **Purpose**: Scales the X and Y dimensions of the keycap body
|
||||
- **Recommendations**:
|
||||
- Start with `0.98` for a 2% reduction
|
||||
- If too tight: try `0.97` (3% reduction)
|
||||
- If too loose: try `0.99` (1% reduction)
|
||||
- Fine-tune: use `0.975`, `0.985`, etc.
|
||||
|
||||
### `body_scale_z`
|
||||
- **Default**: `1.00` (no scaling)
|
||||
- **Purpose**: Scales the Z (height) dimension
|
||||
- **Recommendation**: Keep at `1.00` to maintain keycap height
|
||||
|
||||
### Stem Parameters (Advanced)
|
||||
Only adjust these if the stem preservation isn't working correctly:
|
||||
|
||||
- `stem_diameter`: Diameter of the circular preservation region (default: 5.5mm)
|
||||
- `stem_height`: Height of the stem (default: 4.0mm)
|
||||
- `stem_z_position`: Vertical position offset (default: -2.0mm)
|
||||
- `$fn`: Circle smoothness (default: 64, range: 32-128)
|
||||
|
||||
## How It Works
|
||||
|
||||
The script uses a two-part approach:
|
||||
|
||||
1. **Scaled Body**: The entire keycap is scaled down by your chosen percentage, BUT a circular region around the stem is cut out
|
||||
2. **Original Stem**: The circular stem region is preserved at 100% scale (keeping the 4mm × 4mm Cherry MX cross dimensions)
|
||||
3. **Combined**: Both parts are merged together
|
||||
|
||||
This ensures:
|
||||
- ✅ The outer keycap body fits better in sockets (scaled down)
|
||||
- ✅ The Cherry MX stem remains exactly 4mm × 4mm (unscaled)
|
||||
- ✅ The circular region around the stem is preserved (for off-brand switches)
|
||||
- ✅ The stem stays centered and properly positioned
|
||||
|
||||
## Workflow for Iterative Testing
|
||||
|
||||
1. Export STL with `body_scale_xy = 0.98`
|
||||
2. Slice and print the keycap
|
||||
3. Test fit on your keyboard
|
||||
4. **If too tight**: Decrease scale (try 0.97)
|
||||
5. **If too loose**: Increase scale (try 0.99)
|
||||
6. **If just right**: You're done!
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### The stem looks wrong or is scaled
|
||||
- The circular stem region might not be positioned correctly
|
||||
- Measure your stem in the original STL
|
||||
- Adjust `stem_z_position`, `stem_diameter`, or `stem_height`
|
||||
- If the circle is too jagged, increase `$fn` to 128
|
||||
|
||||
### The keycap won't render
|
||||
- Make sure `Body5.stl` is in the same folder as the `.scad` file
|
||||
- Check for errors in the OpenSCAD console (bottom of window)
|
||||
|
||||
### Rendering is slow
|
||||
- This is normal! The script imports the STL twice
|
||||
- `F5` preview is fast but lower quality
|
||||
- `F6` render is slow but required for STL export
|
||||
- Consider reducing the preview quality in OpenSCAD preferences
|
||||
|
||||
### The seam between body and stem is visible
|
||||
- This is usually not noticeable in the printed part
|
||||
- If needed, increase `stem_diameter` by 0.5mm increments (try 6.0mm or 6.5mm)
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
Key caps/
|
||||
├── Body5.stl # Original keycap STL
|
||||
├── Body5_scaled.scad # OpenSCAD scaling script
|
||||
└── README_scaling.md # This guide
|
||||
```
|
||||
|
||||
## Export Settings
|
||||
|
||||
When exporting STL from OpenSCAD:
|
||||
- File format: STL (binary is smaller, ASCII is more compatible)
|
||||
- Units: millimeters (mm)
|
||||
|
||||
## Next Steps
|
||||
|
||||
After exporting your scaled STL:
|
||||
1. Import into your slicer (Cura, PrusaSlicer, etc.)
|
||||
2. Use typical keycap print settings:
|
||||
- Layer height: 0.1-0.2mm
|
||||
- Infill: 15-20%
|
||||
- Supports: Probably not needed for most keycaps
|
||||
3. Print and test!
|
||||
|
||||
---
|
||||
|
||||
**Note**: The Cherry MX stem dimensions (4mm × 4mm) are standardized. The script is designed to preserve these exactly, so you should only need to adjust the `body_scale_xy` parameter for tolerance testing.
|
||||
34
Printing/Key caps/generate_all_numbered_keycaps.bat
Normal file
34
Printing/Key caps/generate_all_numbered_keycaps.bat
Normal file
@@ -0,0 +1,34 @@
|
||||
@echo off
|
||||
REM =====================================================
|
||||
REM Batch Script to Generate All 20 Numbered Keycaps
|
||||
REM =====================================================
|
||||
REM This script uses OpenSCAD command line to generate
|
||||
REM all 20 numbered keycap STL files automatically
|
||||
REM =====================================================
|
||||
|
||||
echo Starting generation of 20 numbered keycap STL files...
|
||||
echo.
|
||||
|
||||
set OPENSCAD="C:\Program Files\OpenSCAD\openscad.exe"
|
||||
set SCRIPT=generate_numbered_keycaps.scad
|
||||
|
||||
REM Loop through numbers 1-20
|
||||
for /L %%i in (1,1,20) do (
|
||||
echo Generating Body5_num%%i.stl...
|
||||
%OPENSCAD% -D number_to_generate=%%i -o Body5_num%%i.stl %SCRIPT%
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to generate Body5_num%%i.stl
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo Completed Body5_num%%i.stl
|
||||
echo.
|
||||
)
|
||||
|
||||
echo.
|
||||
echo =====================================================
|
||||
echo All 20 numbered keycap STL files generated successfully!
|
||||
echo Files created: Body5_num1.stl through Body5_num20.stl
|
||||
echo =====================================================
|
||||
echo.
|
||||
pause
|
||||
102
Printing/Key caps/generate_numbered_keycaps.scad
Normal file
102
Printing/Key caps/generate_numbered_keycaps.scad
Normal file
@@ -0,0 +1,102 @@
|
||||
// =====================================================
|
||||
// Numbered Keycap Generator - Multi-Color Printing
|
||||
// =====================================================
|
||||
// This script generates 20 numbered keycap STL files
|
||||
// with recessed numbers for multi-material printing
|
||||
//
|
||||
// Numbers are 14mm tall, recessed 0.6mm deep
|
||||
// Positioned on triangular top face, centered on apex-to-midpoint line
|
||||
// Apex oriented as "up" (aligned with Cherry MX cross arm)
|
||||
// =====================================================
|
||||
|
||||
// ----- ADJUSTABLE PARAMETERS -----
|
||||
|
||||
number_to_generate = 1; // Change this value (1-20) to generate different numbers
|
||||
|
||||
number_height = 14; // Height of numbers in mm
|
||||
number_depth = 0.6; // Recess depth for color saturation
|
||||
text_font = "Liberation Sans:style=Bold"; // Font (use bold for visibility)
|
||||
text_thickness = number_depth; // Same as recess depth
|
||||
|
||||
// Triangular face positioning
|
||||
// The top face is opposite the stem pocket
|
||||
// One apex aligns with a Cherry MX cross arm
|
||||
face_z_position = 8.0; // Approximate Z height of top triangular face
|
||||
face_rotation = 0; // Rotation to align apex with cross arm
|
||||
text_y_offset = 0; // Offset along apex-to-midpoint centerline
|
||||
|
||||
$fn = 128; // Circle smoothness
|
||||
|
||||
base_stl_filename = "Body5(1)_scaled_98percent.stl";
|
||||
|
||||
// =====================================================
|
||||
// CENTERED IMPORT MODULE
|
||||
// =====================================================
|
||||
|
||||
module centered_base() {
|
||||
// Import the scaled keycap base
|
||||
// Already centered from the previous scaling script
|
||||
import(base_stl_filename);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// NUMBERED TEXT MODULE
|
||||
// =====================================================
|
||||
|
||||
module recessed_number(num) {
|
||||
// Create text for the number
|
||||
rotate([0, 0, face_rotation]) {
|
||||
translate([0, text_y_offset, face_z_position]) {
|
||||
rotate([0, 0, 0]) { // Text faces up
|
||||
linear_extrude(height = text_thickness + 1) { // +1 to ensure clean cut
|
||||
text(
|
||||
str(num),
|
||||
size = number_height,
|
||||
halign = "center",
|
||||
valign = "center",
|
||||
font = text_font
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// MAIN MODEL
|
||||
// =====================================================
|
||||
|
||||
difference() {
|
||||
// The base keycap
|
||||
centered_base();
|
||||
|
||||
// Subtract the recessed number
|
||||
recessed_number(number_to_generate);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// USAGE INSTRUCTIONS
|
||||
// =====================================================
|
||||
//
|
||||
// MANUAL GENERATION (one at a time):
|
||||
// 1. Change number_to_generate value (1-20)
|
||||
// 2. Render with F6
|
||||
// 3. Export as STL with desired filename
|
||||
//
|
||||
// COMMAND LINE GENERATION (all 20 files):
|
||||
// Use the companion batch script or run:
|
||||
// openscad -D number_to_generate=N -o Body5_numN.stl generate_numbered_keycaps.scad
|
||||
//
|
||||
// ADJUSTING POSITION:
|
||||
// - face_z_position: Move numbers up/down on the keycap
|
||||
// - face_rotation: Rotate around Z axis to align with cross arm
|
||||
// - text_y_offset: Move along the apex-to-midpoint centerline
|
||||
//
|
||||
// MULTI-MATERIAL PRINTING:
|
||||
// 1. Slice the numbered STL normally
|
||||
// 2. At layer with recess (approx 0.6mm from top), insert material change
|
||||
// 3. Printer will pause, swap filament for number color
|
||||
// 4. Resume printing - number will be filled with new color
|
||||
// 5. At end of recess depth, change back to original material
|
||||
//
|
||||
// =====================================================
|
||||
24
Printing/Key caps/index.html
Normal file
24
Printing/Key caps/index.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Directory listing for /Printing/Key caps/</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Directory listing for /Printing/Key caps/</h1>
|
||||
<hr>
|
||||
<ul>
|
||||
<li><a href=".claude/">.claude/</a></li>
|
||||
<li><a href="Body5%281%29_scaled.scad">Body5(1)_scaled.scad</a></li>
|
||||
<li><a href="Body5_scaled.scad">Body5_scaled.scad</a></li>
|
||||
<li><a href="Body5_scaled_FIXED.scad">Body5_scaled_FIXED.scad</a></li>
|
||||
<li><a href="Body5_test_circle.scad">Body5_test_circle.scad</a></li>
|
||||
<li><a href="CLAUDE.md">CLAUDE.md</a></li>
|
||||
<li><a href="generate_all_numbered_keycaps.bat">generate_all_numbered_keycaps.bat</a></li>
|
||||
<li><a href="generate_numbered_keycaps.scad">generate_numbered_keycaps.scad</a></li>
|
||||
<li><a href="README_scaling.md">README_scaling.md</a></li>
|
||||
<li><a href="test_cylinder.scad">test_cylinder.scad</a></li>
|
||||
</ul>
|
||||
<hr>
|
||||
</body>
|
||||
</html>
|
||||
3
Printing/Key caps/test_cylinder.scad
Normal file
3
Printing/Key caps/test_cylinder.scad
Normal file
@@ -0,0 +1,3 @@
|
||||
// Simple cylinder test
|
||||
$fn = 128;
|
||||
cylinder(h = 10, d = 5.0, center = true);
|
||||
1
Printing/Nameplates/.claude/commands
Normal file
1
Printing/Nameplates/.claude/commands
Normal file
@@ -0,0 +1 @@
|
||||
C:/Users/Fred/claude-shared/commands
|
||||
16
Printing/Nameplates/.claude/index.html
Normal file
16
Printing/Nameplates/.claude/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Directory listing for /Printing/Nameplates/.claude/</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Directory listing for /Printing/Nameplates/.claude/</h1>
|
||||
<hr>
|
||||
<ul>
|
||||
<li><a href="commands">commands</a></li>
|
||||
<li><a href="settings.local.json">settings.local.json</a></li>
|
||||
</ul>
|
||||
<hr>
|
||||
</body>
|
||||
</html>
|
||||
36
Printing/Nameplates/.claude/settings.local.json
Normal file
36
Printing/Nameplates/.claude/settings.local.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(python:*)",
|
||||
"Bash(dir:*)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -D \"name=\"\"Test\"\"\" -o test_output.stl nameplate_template.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -o checkmark_test.stl checkmark_template.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -D \"name=\"\"Test\"\"\" -o test_hole_position.stl zipper_pull_template.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -D \"name=\"\"Christopher\"\"\" -o test_christopher.stl zipper_pull_template.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -D \"name=\"\"Christopher\"\"\" -o test_christopher_13pt.stl zipper_pull_template.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -D \"name=\"\"Fred\"\"\" -o test_fred_bold.stl zipper_pull_template.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -D \"name=\"\"Zoe\"\"\" -o test_zoe.stl zipper_pull_template.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -D \"name=\"\"Fred\"\"\" -o test_fred_dynamic.stl zipper_pull_template.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -D \"name=\"\"Christopher\"\"\" -o test_christopher_dynamic.stl zipper_pull_template.scad)",
|
||||
"Bash(timeout:*)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -D \"name=\"\"Zoe\"\"\" -o test_zoe_raised.stl zipper_pull_raised_text_template.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -D \"name=\"\"Fred\"\"\" -o test_fred_raised.stl zipper_pull_raised_text_template.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -D \"name=\"\"Christopher\"\"\" -o test_christopher_raised.stl zipper_pull_raised_text_template.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -D \"name=\"\"Fred\"\"\" -D \"base_text_size=13\" -o test_fred_debug.stl zipper_pull_raised_text_template.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -o test_simple_fred.stl test_simple_fred.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -D \"name=\"\"Fred\"\"\" -o test_fred_reduced_bold.stl zipper_pull_raised_text_template_REDUCED_BOLD.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -D \"name=\"\"Bennet\"\"\" -o test_bennet_facedown.stl zipper_pull_raised_text_template.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -D \"name=\"\"Bennett\"\"\" -o test_bennett_facedown.stl zipper_pull_raised_text_template.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -D \"name=\"\"Bennett\"\"\" -o test_bennett_facedown.3mf zipper_pull_raised_text_template.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -o test_font.stl test_font.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -o test_debug.3mf test_debug.scad)",
|
||||
"Bash(\"C:\\Program Files\\OpenSCAD\\openscad.exe\" -o test_blue_only.3mf test_blue_only.scad)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
},
|
||||
"enableAllProjectMcpServers": true,
|
||||
"enabledMcpjsonServers": [
|
||||
"n8n-mcp"
|
||||
]
|
||||
}
|
||||
278
Printing/Nameplates/.github/copilot-instructions.md
vendored
Normal file
278
Printing/Nameplates/.github/copilot-instructions.md
vendored
Normal file
@@ -0,0 +1,278 @@
|
||||
# AI Coding Instructions for Nameplates Generator
|
||||
|
||||
## Project Overview
|
||||
|
||||
A batch 3D nameplate generator using **Python + OpenSCAD**. Reads names from text file, generates parametric two-layer oval nameplates with engraved text, outputs STL files for 3D printing.
|
||||
|
||||
**Design**: White base (1.5mm) + blue top layer (1mm) with text engraved through blue layer to expose white underneath.
|
||||
|
||||
## Critical Dependencies
|
||||
|
||||
### OpenSCAD Installation
|
||||
- **Path**: `C:\Program Files\OpenSCAD\openscad.exe` (hardcoded in line 36 of `generate_nameplates.py`)
|
||||
- Download: https://openscad.org/downloads.html
|
||||
- **Must update path** if installed elsewhere
|
||||
|
||||
### Font Requirements (CRITICAL)
|
||||
- **Font**: Fordscript cursive font (`Fordscript.ttf` in project root)
|
||||
- **Installation**: Must be installed in Windows (right-click → Install for all users)
|
||||
- **Why**: OpenSCAD references fonts by name, not file path
|
||||
- **Reference in SCAD**: `font="Fordscript"` (line 44 of `nameplate_template.scad`)
|
||||
- **Path hardcoded**: `font_file = "C:/Users/Fred/claude/Fordscript.ttf"` in SCAD (line 10) - informational only, not used by OpenSCAD
|
||||
|
||||
## Architecture & Data Flow
|
||||
|
||||
```
|
||||
names.txt → generate_nameplates.py → OpenSCAD CLI → output_stl/*.stl
|
||||
↑
|
||||
nameplate_template.scad
|
||||
```
|
||||
|
||||
### Pipeline
|
||||
1. **Input**: `names.txt` (one name per line, UTF-8 encoded)
|
||||
2. **Processing**: Python script iterates, calling OpenSCAD for each name
|
||||
3. **OpenSCAD**: Renders 3D model from parametric template
|
||||
4. **Output**: Individual STL files in `output_stl/` directory
|
||||
|
||||
### Key Files
|
||||
- `generate_nameplates.py` - Batch processor, subprocess orchestration
|
||||
- `nameplate_template.scad` - Parametric OpenSCAD template
|
||||
- `names.txt` - Input data (plain text, one name per line)
|
||||
- `output_stl/` - Generated STL files (created automatically)
|
||||
- `Fordscript.ttf` - Custom font (must be installed)
|
||||
|
||||
## Critical Developer Workflows
|
||||
|
||||
### Generate All Nameplates
|
||||
```bash
|
||||
python generate_nameplates.py
|
||||
```
|
||||
|
||||
### Test Single Nameplate (Manual)
|
||||
```powershell
|
||||
# PowerShell syntax
|
||||
& "C:\Program Files\OpenSCAD\openscad.exe" -D 'name="TestName"' -o test_output.stl nameplate_template.scad
|
||||
|
||||
# Or from CMD
|
||||
"C:\Program Files\OpenSCAD\openscad.exe" -D "name=\"TestName\"" -o test_output.stl nameplate_template.scad
|
||||
```
|
||||
|
||||
### Preview in OpenSCAD GUI
|
||||
```powershell
|
||||
# Open template in GUI for visual editing
|
||||
& "C:\Program Files\OpenSCAD\openscad.exe" nameplate_template.scad
|
||||
```
|
||||
|
||||
Then manually edit `name` parameter at top of file to preview different text.
|
||||
|
||||
### Validate Font Installation
|
||||
```powershell
|
||||
# Check if font is installed
|
||||
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" | Select-String "Fordscript"
|
||||
|
||||
# Or check fonts directory
|
||||
ls $env:WINDIR\Fonts\Fordscript*
|
||||
```
|
||||
|
||||
## Project-Specific Conventions
|
||||
|
||||
### Name Sanitization
|
||||
Python script converts names to safe filenames:
|
||||
- Removes special characters (keeps alphanumeric, spaces, hyphens, underscores)
|
||||
- Replaces spaces with underscores
|
||||
- Example: `"John Doe"` → `John_Doe.stl`
|
||||
|
||||
### OpenSCAD Command Pattern
|
||||
```python
|
||||
cmd = [
|
||||
r'C:\Program Files\OpenSCAD\openscad.exe',
|
||||
'-D', f'name="{escaped_name}"', # Set variable
|
||||
'-o', output_file, # Output file
|
||||
template_file # Input SCAD file
|
||||
]
|
||||
```
|
||||
|
||||
**Key flags**:
|
||||
- `-D name="value"` - Override parameter in SCAD file
|
||||
- `-o file.stl` - Output file path
|
||||
- No flag for input file (positional argument)
|
||||
|
||||
### SCAD Template Structure
|
||||
```scad
|
||||
// Parameters (overridable via -D flag)
|
||||
name = "NAME";
|
||||
oval_width = 100;
|
||||
oval_height = 38;
|
||||
// ... more parameters
|
||||
|
||||
// Modules (functions)
|
||||
module oval(width, height, depth) { ... }
|
||||
module base_layer() { ... }
|
||||
module top_layer() { ... }
|
||||
module nameplate() { ... }
|
||||
|
||||
// Execution (builds the model)
|
||||
nameplate();
|
||||
```
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
### Font Not Found Error
|
||||
**Symptom**: OpenSCAD renders but text is missing or uses default font.
|
||||
|
||||
**Causes**:
|
||||
1. Font not installed in Windows (right-click TTF → Install)
|
||||
2. Font name mismatch (must be exactly "Fordscript" in SCAD)
|
||||
3. OpenSCAD needs restart after font installation
|
||||
|
||||
**Fix**: Install font, restart OpenSCAD, verify with manual test.
|
||||
|
||||
### Special Characters in Names
|
||||
**Symptom**: Subprocess error or malformed STL.
|
||||
|
||||
**Cause**: Shell escaping issues with quotes, backslashes, etc.
|
||||
|
||||
**Current handling**: `escaped_name = name.replace('"', '\\"')` (line 33)
|
||||
|
||||
**Extension**: Add more sanitization if needed:
|
||||
```python
|
||||
# Escape more shell-sensitive characters
|
||||
escaped_name = name.replace('"', '\\"').replace('\\', '\\\\')
|
||||
```
|
||||
|
||||
### OpenSCAD Path Issues
|
||||
**Symptom**: `FileNotFoundError: OpenSCAD not found`.
|
||||
|
||||
**Fix**: Update hardcoded path in `generate_nameplates.py:36`:
|
||||
```python
|
||||
cmd = [
|
||||
r'C:\Program Files\OpenSCAD\openscad.exe', # ← Update this
|
||||
# ...
|
||||
]
|
||||
```
|
||||
|
||||
**Better approach**: Use environment variable or config file:
|
||||
```python
|
||||
OPENSCAD_PATH = os.getenv('OPENSCAD_PATH', r'C:\Program Files\OpenSCAD\openscad.exe')
|
||||
```
|
||||
|
||||
## Modifying Dimensions
|
||||
|
||||
All dimensions in `nameplate_template.scad` (lines 6-12):
|
||||
|
||||
| Parameter | Current Value | Purpose |
|
||||
|-----------|---------------|---------|
|
||||
| `oval_width` | 100mm | Overall width |
|
||||
| `oval_height` | 38mm | Overall height (proportional) |
|
||||
| `base_thickness` | 1.5mm | White layer thickness |
|
||||
| `top_thickness` | 1mm | Blue layer thickness |
|
||||
| `base_offset` | 2mm | White extension beyond blue |
|
||||
| `text_size` | 15mm | Font size |
|
||||
| `text_depth` | 1mm | Engraving depth (full blue layer) |
|
||||
|
||||
### Maintaining Proportions
|
||||
Height typically 38% of width for aesthetic oval shape:
|
||||
```scad
|
||||
oval_height = oval_width * 0.38;
|
||||
```
|
||||
|
||||
### Text Depth Critical
|
||||
`text_depth` must equal `top_thickness` to engrave through entire blue layer:
|
||||
```scad
|
||||
text_depth = 1; // Must match top_thickness for full engraving
|
||||
```
|
||||
|
||||
If `text_depth < top_thickness`, text won't reach white base. If `text_depth > top_thickness`, text cuts into white base (undesirable).
|
||||
|
||||
## Extending the Template
|
||||
|
||||
### Add New Shape Option
|
||||
```scad
|
||||
// Add rectangle module
|
||||
module rectangle(width, height, depth) {
|
||||
cube([width, height, depth], center=true);
|
||||
}
|
||||
|
||||
// Add shape parameter at top
|
||||
shape = "oval"; // or "rectangle"
|
||||
|
||||
// Use conditional in base_layer
|
||||
module base_layer() {
|
||||
if (shape == "rectangle")
|
||||
rectangle(oval_width + base_offset*2, oval_height + base_offset*2, base_thickness);
|
||||
else
|
||||
oval(oval_width + base_offset*2, oval_height + base_offset*2, base_thickness);
|
||||
}
|
||||
```
|
||||
|
||||
### Add Logo/Icon
|
||||
```scad
|
||||
// Import SVG or PNG
|
||||
module logo() {
|
||||
translate([0, -oval_height/3, base_thickness + top_thickness - text_depth])
|
||||
linear_extrude(height=text_depth)
|
||||
import("logo.svg", center=true);
|
||||
}
|
||||
|
||||
// Add to top_layer difference
|
||||
difference() {
|
||||
// ... existing blue oval
|
||||
logo(); // Cut logo
|
||||
}
|
||||
```
|
||||
|
||||
### Batch Different Sizes
|
||||
Modify Python script to pass multiple parameters:
|
||||
```python
|
||||
cmd = [
|
||||
r'C:\Program Files\OpenSCAD\openscad.exe',
|
||||
'-D', f'name="{escaped_name}"',
|
||||
'-D', f'oval_width={width}', # Variable width
|
||||
'-D', f'text_size={text_size}', # Variable text size
|
||||
'-o', output_file,
|
||||
template_file
|
||||
]
|
||||
```
|
||||
|
||||
## Troubleshooting Commands
|
||||
|
||||
```powershell
|
||||
# Check OpenSCAD version
|
||||
& "C:\Program Files\OpenSCAD\openscad.exe" --version
|
||||
|
||||
# Test SCAD syntax (no output, just validation)
|
||||
& "C:\Program Files\OpenSCAD\openscad.exe" --check nameplate_template.scad
|
||||
|
||||
# Render with verbose output
|
||||
& "C:\Program Files\OpenSCAD\openscad.exe" -D 'name="Test"' -o test.stl nameplate_template.scad --verbose
|
||||
|
||||
# List available fonts in OpenSCAD (run in OpenSCAD console)
|
||||
# Help → Font List
|
||||
```
|
||||
|
||||
## 3D Printing Notes
|
||||
|
||||
- **Material**: Two colors required (white + blue recommended)
|
||||
- **Layer Height**: 0.1-0.2mm for clean text
|
||||
- **Infill**: 20-30% sufficient for thin nameplates
|
||||
- **Supports**: Not needed (flat design)
|
||||
- **Orientation**: Print flat (as modeled)
|
||||
- **Bed Adhesion**: Brim or raft recommended for thin parts
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Add New Name
|
||||
1. Edit `names.txt`, add line with new name
|
||||
2. Run `python generate_nameplates.py`
|
||||
3. Find STL in `output_stl/` directory
|
||||
|
||||
### Change All Dimensions
|
||||
1. Edit parameters at top of `nameplate_template.scad`
|
||||
2. Run `python generate_nameplates.py` to regenerate all
|
||||
3. Or manually test with single name first
|
||||
|
||||
### Install Font on New Machine
|
||||
1. Copy `Fordscript.ttf` to new machine
|
||||
2. Right-click → "Install for all users"
|
||||
3. Restart OpenSCAD if running
|
||||
4. Test with manual OpenSCAD command
|
||||
15
Printing/Nameplates/.github/index.html
vendored
Normal file
15
Printing/Nameplates/.github/index.html
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Directory listing for /Printing/Nameplates/.github/</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Directory listing for /Printing/Nameplates/.github/</h1>
|
||||
<hr>
|
||||
<ul>
|
||||
<li><a href="copilot-instructions.md">copilot-instructions.md</a></li>
|
||||
</ul>
|
||||
<hr>
|
||||
</body>
|
||||
</html>
|
||||
BIN
Printing/Nameplates/300.103.pdf
Normal file
BIN
Printing/Nameplates/300.103.pdf
Normal file
Binary file not shown.
68
Printing/Nameplates/CLAUDE.md
Normal file
68
Printing/Nameplates/CLAUDE.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
This is a 3D nameplate generator that creates two-layer oval nameplates with engraved text using OpenSCAD. The system batch-processes names from a text file and outputs STL files ready for 3D printing.
|
||||
|
||||
## Architecture
|
||||
|
||||
**Pipeline:**
|
||||
1. Python script (`generate_nameplates.py`) reads names from `names.txt`
|
||||
2. For each name, it invokes OpenSCAD CLI with the parametric template
|
||||
3. OpenSCAD renders the 3D model using `nameplate_template.scad`
|
||||
4. STL files are output to `output_stl/` directory
|
||||
|
||||
**Design Structure:**
|
||||
- Two-layer design: white base (1.5mm) + blue top layer (1mm)
|
||||
- Text is engraved completely through the blue layer to expose white underneath
|
||||
- Oval shape created by scaling a cylinder
|
||||
- All dimensions parametric for easy customization
|
||||
|
||||
## Key Commands
|
||||
|
||||
**Generate nameplates:**
|
||||
```bash
|
||||
python generate_nameplates.py
|
||||
```
|
||||
|
||||
**Test single nameplate (manual):**
|
||||
```bash
|
||||
"C:\Program Files\OpenSCAD\openscad.exe" -D "name=\"TestName\"" -o output.stl nameplate_template.scad
|
||||
```
|
||||
|
||||
## Critical Configuration
|
||||
|
||||
**OpenSCAD Path:**
|
||||
The script uses hardcoded path: `C:\Program Files\OpenSCAD\openscad.exe`
|
||||
Update in `generate_nameplates.py:36` if OpenSCAD is installed elsewhere.
|
||||
|
||||
**Font Requirements:**
|
||||
- Uses Fordscript font (Fordscript.ttf in project root)
|
||||
- Font MUST be installed in Windows (right-click → Install) for OpenSCAD to access it
|
||||
- OpenSCAD references fonts by name, not file path
|
||||
- Referenced in template as `font="Fordscript"` (line 44)
|
||||
|
||||
**Dimensions:**
|
||||
Default nameplate size: 3" tall × 8" wide (76mm × 200mm)
|
||||
All dimensions in `nameplate_template.scad:6-12`
|
||||
|
||||
## File Purposes
|
||||
|
||||
- `nameplate_template.scad` - OpenSCAD parametric template defining the 3D geometry
|
||||
- `generate_nameplates.py` - Batch processor that calls OpenSCAD for each name
|
||||
- `names.txt` - Input file with one name per line
|
||||
- `Fordscript.ttf` - Custom cursive font (must be installed in Windows)
|
||||
- `output_stl/` - Generated STL files (one per name)
|
||||
|
||||
## Modifying Dimensions
|
||||
|
||||
Key parameters in `nameplate_template.scad`:
|
||||
- `oval_height` - Overall height (currently 76mm = 3 inches)
|
||||
- `oval_width` - Overall width (currently 200mm ≈ 8 inches)
|
||||
- `base_thickness` - White layer thickness (1.5mm)
|
||||
- `top_thickness` - Blue layer thickness (1mm)
|
||||
- `text_depth` - Engraving depth (1mm - cuts through entire blue layer)
|
||||
- `text_size` - Font size (30mm)
|
||||
- `base_offset` - How much white extends beyond blue (2mm)
|
||||
19092
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 01.dxf
Normal file
19092
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 01.dxf
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 01.eps
Normal file
BIN
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 01.eps
Normal file
Binary file not shown.
BIN
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 01.png
Normal file
BIN
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 01.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 136 KiB |
56
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 01.svg
Normal file
56
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 01.svg
Normal file
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 720 570.9" style="enable-background:new 0 0 720 570.9;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#7E4E8C;}
|
||||
.st1{fill:#9C6BAD;}
|
||||
</style>
|
||||
<g id="XMLID_3_">
|
||||
<path id="XMLID_188_" d="M717.3,120.1l-1.3-2.8l-0.3-0.8l-0.3-0.5l-0.5-1l-0.5-1l-0.3-0.5v-0.3c-0.5-1-0.3-0.5-0.5-0.8l-1.6-2.3
|
||||
c-1-1.6-2.3-2.8-3.4-4.4c-1.3-1.3-2.6-2.6-3.9-3.9c-11.1-9.8-27.4-13.2-41.4-8.8c-1.8,0.5-3.9,1.3-5.7,2.1l-1.8,1l-1,0.5l-0.8,0.5
|
||||
l-0.5,0.3l-7.2,4.4l-14.8,8.5l-29.2,17.1L582.3,139c0-11.9,0-24.1,0.3-36.2c0-7.2,0-14.2,0-21.5c0-3.6,0-7.2,0-10.9
|
||||
c0-2.1-0.3-4.1-0.3-6.2s-0.5-4.1-0.8-6.2c-2.8-16.8-12.2-32.6-26.1-43.2c-7-5.4-14.8-9.3-23.3-11.9c-2.1-0.5-4.1-1.3-6.5-1.6
|
||||
c-2.3-0.3-4.9-0.8-7-1L512.9,0h-6.2c-15.3,0-30.5,0.3-46.1,0.3c-62.1,0.3-126.3,1.3-191.5,1.8c-65.2,0.8-131.5,1-197.7,1
|
||||
c-18.6-0.3-37,8-49.4,21.5c-6.2,6.7-11.1,14.8-14.2,23.5c-1.6,4.4-2.6,8.8-3.4,13.7c0,0.5-0.3,1.3-0.3,1.8v1.6l-0.3,3.1v0.8v1v4.7
|
||||
c0,33.1-0.5,65.7-0.8,98.6C2.3,238.6,1.8,302.8,1,364.9c-0.3,31.1-0.5,61.6-0.8,91.6C0,471.5,0,486.2,0,501
|
||||
c0,8.5,1.8,17.3,4.9,25.4c3.1,8,7.8,15.3,13.5,21.5c5.7,6.2,12.4,11.4,19.7,15.3l5.7,2.6c2.1,0.8,3.9,1.3,6,2.1
|
||||
c3.9,1,7.8,2.1,12.4,2.6c1,0.3,2.3,0.3,3.1,0.5h2.6h2.6h0.8c1.3,0,0.8,0,1.3,0h1.3c3.4,0,6.7,0,10.4,0c6.7,0,13.7,0,20.2-0.3
|
||||
c26.9-0.3,52.8-0.5,77.6-0.8c49.7-0.5,95.2-1,135.6-1.6c40.4-0.5,75.6-0.8,104.5-0.8c58-0.3,91.1-0.5,91.1-0.5s2.3,0,6.7-0.3
|
||||
c4.4-0.8,11.1-1.6,19.1-4.9s17.3-9.3,25.4-18.9c3.9-4.9,7.8-10.6,10.6-17.1c0.5-1.8,1.3-3.4,1.8-5.2c0.5-1.8,1-3.6,1.6-5.4
|
||||
c0.5-1.8,0.8-3.9,1-6c0.3-1,0.3-2.1,0.5-3.1c0-0.8,0-1.8,0-2.6s0-1.8,0.3-2.8v-1v-2.1c0-1.8,0-3.6,0-5.7c0-3.9,0-7.8,0-11.6
|
||||
c0-8,0-16.3,0-25.1c0-17.6,0.3-36.5,0.3-56.7c0.3-40.4,0.8-85.9,1-135.6c0-7.5,0.3-15.3,0.3-23l24.6-14.2l58.7-34.2l29.2-17.1
|
||||
l3.6-2.1c1.3-0.8,3.1-2.1,4.7-3.1c2.8-2.3,5.7-4.9,8-7.8c4.7-5.7,7.8-12.9,9.1-20.2C720.4,134.6,719.9,127.1,717.3,120.1z
|
||||
M368.2,265.5l-111.5,66c-8.5-11.1-17.1-22.3-25.6-33.1l-29.5-38.3l-7.5-9.3c-0.8-0.8-1-1.6-2.1-2.6c-0.8-1-1.6-2.1-2.6-2.8
|
||||
l-2.8-2.6c-1-0.8-2.1-1.6-3.1-2.3c-8.5-6-19.1-8.8-29.2-7.5c-5.2,0.5-10.4,2.1-15,4.4c-1.3,0.8-2.6,1.3-3.9,2.1
|
||||
c-0.8,0.5-1,0.8-1.3,1l-1.3,0.8l-0.5,0.5l-0.5,0.5l-0.5,0.5l-1.6,1.3c-1,0.8-1.8,1.8-2.8,2.8c-7.2,7.8-11.4,17.9-11.6,28.5
|
||||
c0,5.2,0.8,10.6,2.6,15.5c0.3,1.3,1,2.6,1.6,3.6l0.8,1.8l1,2.1l1,1.8c0.5,0.8,0.5,0.8,1,1.3l0.8,1.3l0.3,0.3v0.3l0.5,0.5l0.5,0.5
|
||||
l15,18.9l30,37.5l30.3,37.5l7.5,9.3l3.9,4.7c1.6,2.1,3.4,3.9,5.4,5.7c4.1,3.6,8.8,6.5,13.7,8.3c2.6,1,5.2,1.6,7.8,2.1
|
||||
c1.3,0.3,2.6,0.5,4.1,0.5h1c0.3,0,0.8,0,1,0h1.6h0.3c7.5,0,15.3-2.1,21.7-5.7l14.8-8.5l29.2-17.1l58.7-34.2L488.6,295l7.5-4.4
|
||||
L494,482.9c-5.2,0-10.4,0-15.5,0l-26.7,0.3l-53.6,0.5l-106.9,1L84.6,487c0.5-32.3,0.8-64.7,1.3-97l0.8-104.3l0.5-52v-52.3l0.3-94.2
|
||||
h43.5l53.6-0.3l106.9-0.3l106.9-1l53.6-0.8c15.5-0.3,30.8-0.5,46.3-0.8l-1,105.1l-12.4,7.2L368.2,265.5z"/>
|
||||
<path id="XMLID_28_" class="st0" d="M565.4,498.4c0-1.8,0-3.6,0-5.7c0-3.9,0-7.8,0-11.6c0-8,0-16.3,0-25.1
|
||||
c0-17.6-0.3-36.5-0.5-56.7c-0.3-40.4-0.8-85.9-1-135.6c0-4.1,0-8.3,0-12.4l-48.7,28.5l2.3,214.3c0,6.2-4.9,11.4-11.1,11.4l0,0h-0.3
|
||||
c-8.8,0-17.9,0-26.7,0l-26.7-0.3l-53.6-0.5L78.4,501c-3.9,0-7-3.1-7-7l0,0c-0.5-34.7-1-69.6-1.3-104.3l-0.8-104.3l-0.3-52v-52
|
||||
L68.8,77.1c0-5.4,4.4-9.8,9.8-10.1l0,0h53.6l53.6,0.3l106.9,0.3l106.9,1l53.6,0.8c17.9,0.3,35.7,0.5,53.6,0.8l0,0c3.9,0,7,3.1,7,7
|
||||
l1,102.5l49.2-28.7c0-15.5,0-31.6-0.3-47.6c0-7.2,0-14.2,0-21.5c0-3.6,0-7.2,0-10.9c0-1.8-0.3-3.1-0.3-4.7c0-1.6-0.5-3.1-0.5-4.4
|
||||
c-2.1-11.9-8.8-23.3-18.9-30.8c-4.9-3.9-10.6-6.7-16.6-8.5c-1.6-0.3-3.1-0.8-4.4-1c-1.6-0.3-2.6-0.5-4.4-0.8l-5.7-0.3h-5.2
|
||||
c-15.3,0-30.5-0.3-46.1-0.3c-62.1-0.3-126.3-1.3-191.5-1.8c-65.2-0.8-131.5-1-197.7-1c-14.8,0-29,6.5-38.8,17.3
|
||||
c-4.9,5.4-8.8,11.6-11.1,18.6c-1.3,3.4-2.1,7-2.3,10.4c0,0.5-0.3,0.8-0.3,1.3v1.6l-0.3,3.9c0,0.3,0,0.3,0,0.3l0,0v1.6v3.1
|
||||
c0,33.1,0.3,66,0.8,98.6c0.8,65.2,1.3,129.4,2.1,191.5c0.3,31.1,0.5,61.6,0.8,91.6c0.3,15,0.3,29.8,0.5,44.3
|
||||
c0,11.9,4.7,23.3,12.4,32.1c3.9,4.4,8.3,8,13.5,10.9l3.9,1.8l3.9,1.6c2.6,0.8,5.4,1.6,8,1.8c0.5,0,1.3,0.3,1.8,0.3l2.6,0.3l2.6,0.3
|
||||
H73h0.3h1.3c3.4,0,6.7,0,10.4,0c6.7,0,13.5,0.3,20.2,0.3c26.9,0.3,52.8,0.5,77.6,0.8c49.7,0.5,95.2,1,135.6,1.6
|
||||
c40.4,0.5,75.6,0.8,104.5,0.8c58,0.3,91.1,0.3,91.1,0.3s1.8,0,5.4-0.3c3.4-0.5,8.8-1,15-3.9c6.2-2.6,13.7-7.2,20.2-14.8
|
||||
c3.1-3.9,6-8.3,8.3-13.7c0.5-1.3,1-2.6,1.6-4.1c0.5-1.3,0.8-2.8,1.3-4.4c0.5-1.6,0.5-2.8,0.8-4.4c0-0.8,0.3-1.3,0.3-2.1
|
||||
s0-1.8,0-2.6s0-1.8,0-2.8v-0.3l0,0v-0.8L565.4,498.4z"/>
|
||||
<path id="XMLID_29_" class="st1" d="M691.5,117.5c-5.7-5.2-14.5-7.2-22-4.9c-0.5,0-0.8,0.3-1.3,0.5c-0.3,0.3-0.8,0.3-1,0.3l-1.8,1
|
||||
l-1,0.5l0,0l0,0l-0.5,0.3l-7.2,4.1l-14.8,8.5l-29.5,16.8l-117.7,67.5l-118,67.3l-118,67.3c-3.1,1.8-7,1-9.1-1.6l0,0l0,0
|
||||
c-10.4-12.2-20.7-24.3-31.1-36.7l-31.1-36.7l-7.8-9.3c-0.5-0.8-1.3-1.6-1.8-2.1l-1.6-1.6l-1.6-1.3c-0.5-0.5-1.3-0.8-1.8-1.3
|
||||
c-4.7-3.1-10.6-4.4-16.3-3.9c-2.8,0.3-5.4,1.3-8,2.6c-0.5,0.3-1,0.5-1.6,0.8c-0.3,0-0.8,0.5-1,0.8l-1.3,0.8l-0.3,0.3l0,0l0,0
|
||||
l-0.3,0.3l-0.8,0.8c-0.5,0.5-1,1-1.6,1.6c-3.6,4.1-5.7,9.6-5.7,15.3c0,2.8,0.5,5.4,1.6,8c0.3,0.8,0.5,1.3,0.8,1.8l0.5,1l0.5,0.8
|
||||
l0.3,0.8c0,0.3,0.5,0.8,0.8,1l0.8,1.3l0.3,0.3l0.5,0.5l15.3,18.6l30.5,37.3l30.3,37.3l7.5,9.3l3.9,4.7c1,1,1.8,2.1,2.8,2.8
|
||||
c2.1,1.8,4.4,3.1,6.7,3.9c1.3,0.5,2.6,0.8,3.9,1c0.5,0,1.3,0.3,1.8,0.3h0.3c0,0,0.3,0,0.5,0h1.3c3.6,0,7.5-1,10.6-2.8l14.5-8.3
|
||||
l29.5-17.1l58.7-33.9l117.5-68.1l117.5-68.1l58.7-33.9l29.5-16.8l3.6-2.1c1-0.8,1.8-1,2.6-1.6c1.6-1.3,3.1-2.6,4.1-3.9
|
||||
c2.6-2.8,4.1-6.7,4.9-10.6c0.5-3.9,0.3-8-1-11.4C696.6,123.4,694.3,120.1,691.5,117.5z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.7 KiB |
19050
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 02.dxf
Normal file
19050
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 02.dxf
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 02.eps
Normal file
BIN
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 02.eps
Normal file
Binary file not shown.
BIN
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 02.png
Normal file
BIN
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 02.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
50
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 02.svg
Normal file
50
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 02.svg
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 720 570.7" style="enable-background:new 0 0 720 570.7;" xml:space="preserve">
|
||||
<path id="XMLID_42_" d="M717.1,120l-1.3-2.8l-0.3-0.8l-0.3-0.5l-0.5-1l-0.5-1l-0.3-0.5V113c-0.5-1-0.3-0.5-0.5-0.8l-1.6-2.3
|
||||
c-1-1.6-2.3-2.8-3.4-4.4c-1.3-1.3-2.6-2.6-3.9-3.9c-11.1-9.8-27.4-13.2-41.4-8.8c-1.8,0.5-3.9,1.3-5.7,2.1l-1.8,1l-1,0.5l-1,0.5
|
||||
l-0.5,0.3l-7.2,4.4l-14.7,8.5L602,127.3l-20.2,11.6c0-11.9,0-24.1,0.3-36.2c0-7.2,0-14.2,0-21.5c0-3.6,0-7.2,0-10.9
|
||||
c0-1.8-0.3-4.1-0.3-6.2c0-2.1-0.5-4.1-0.8-6.2c-2.8-16.8-12.2-32.6-26.1-43.2c-7-5.4-14.7-9.3-23.3-11.9c-2.1-0.5-4.1-1-6.5-1.6
|
||||
c-2.3-0.3-4.9-0.8-7-1L512.5,0h-6.2c-15.3,0-30.5,0.3-46,0.3C398.1,0.5,334,1.6,268.8,2.1c-65.2,0.8-131.4,1-197.6,1
|
||||
c-18.6-0.3-37,8-49.4,21.5c-6.2,6.7-11.1,14.7-14.2,23.5c-1.6,4.4-2.6,8.8-3.1,13.7c0,0.5-0.3,1.3-0.3,1.8v1.6l-0.3,3.1v0.8v1v1.6
|
||||
v3.1c0,33.1-0.3,66-0.8,98.6C2.3,238.5,1.8,302.7,1,364.8c-0.3,31-0.5,61.6-0.8,91.6c0,15-0.3,29.7-0.3,44.5
|
||||
c0,8.8,1.8,17.3,4.9,25.4c3.1,8,7.8,15.3,13.5,21.5c5.7,6.2,12.4,11.4,19.7,15.3l5.7,2.6c1.8,0.8,3.9,1.3,5.9,2.1
|
||||
c3.9,1,7.8,2.1,12.4,2.6c1,0.3,2.3,0.3,3.1,0.5h2.6h2.6h0.5c1.3,0,0.8,0,1.3,0h1.3c3.4,0,6.7,0,10.3,0c6.7,0,13.5-0.3,20.2-0.3
|
||||
c26.9-0.3,52.8-0.5,77.6-0.8c49.7-0.5,95.2-1,135.6-1.6c40.4-0.5,75.5-0.8,104.5-0.8c57.9-0.3,91.1-0.3,91.1-0.3s2.3,0,6.7-0.3
|
||||
c4.4-0.5,11.1-1.6,19.1-4.9s17.3-9.3,25.6-18.6c3.9-4.9,7.8-10.6,10.6-17.1c0.5-1.8,1.3-3.4,1.8-5.2c0.5-1.8,1-3.6,1.6-5.4
|
||||
c0.5-1.8,0.8-3.9,1-5.9c0.3-1,0.3-2.1,0.5-3.1c0-0.8,0-1.8,0.3-2.6c0-0.8,0-1.8,0.3-2.8v-1v-0.8V498c0-1.8,0-3.6,0-5.7
|
||||
c0-3.9,0-7.8,0-11.6c0-8,0-16.3,0-25.1c0-17.6,0.3-36.5,0.5-56.7c0.3-40.4,0.8-85.9,1-135.6c0-7.5,0-15.3,0.3-23l24.6-14.2
|
||||
l58.7-34.1l29.2-17.1l3.6-2.1c1.3-0.8,3.1-1.8,4.7-3.1c2.8-2.3,5.7-4.9,8-7.8c4.7-5.7,7.8-12.9,9.1-20.2
|
||||
C720.2,134.5,719.7,127,717.1,120z M563.7,263.6c0.5,49.7,0.8,95.2,1,135.6c0.3,20.2,0.3,39.1,0.5,56.7c0,8.8,0,17.1,0,25.1
|
||||
c0,3.9,0,8,0,11.6c0,1.8,0,3.9,0,5.7v1.3v0.8l0,0v0.3c0,1,0,1.8,0,2.8c0,0.8,0,1.8,0,2.6c0,0.8-0.3,1.6-0.3,2.1
|
||||
c-0.3,1.6-0.3,2.8-0.8,4.4c-0.5,1.6-0.8,2.8-1.3,4.4c-0.5,1.3-1,2.8-1.6,4.1c-2.3,5.2-5.2,9.8-8.3,13.7
|
||||
c-6.5,7.5-13.7,12.2-20.2,14.7c-6.2,2.6-11.6,3.4-15,3.9c-3.6,0.3-5.4,0.3-5.4,0.3s-33.1-0.3-91.1-0.3c-29,0-64.2-0.3-104.5-0.8
|
||||
c-40.4-0.5-85.9-1-135.6-1.6c-24.8-0.3-50.7-0.5-77.6-0.8c-6.7,0-13.5-0.3-20.2-0.3c-3.4,0-6.7,0-10.3,0h-1.3c0,0,0,0-0.3,0h-0.5
|
||||
l-2.6-0.3l-2.6-0.3c-0.8,0-1.3-0.3-1.8-0.3c-2.3-0.3-5.2-1-8-1.8l-3.9-1.6l-3.9-1.8c-4.9-2.8-9.6-6.5-13.5-10.9
|
||||
c-7.5-8.8-12.2-20.2-12.4-32.1c-0.3-14.5-0.3-29.2-0.5-44.2c-0.3-30-0.5-60.5-0.8-91.6c-0.8-62.1-1.3-126.2-2.1-191.4
|
||||
c-0.3-32.6-0.5-65.4-0.8-98.6v-3.1v-1.6l0,0c0,0,0,0,0-0.3l0.3-3.9v-1.6c0-0.5,0.3-0.8,0.3-1.3c0.5-3.1,1.3-6.7,2.3-10.3
|
||||
c2.3-6.7,6.2-13.2,11.1-18.6c9.8-10.9,24.1-17.3,38.8-17.3c66.2,0,132.5,0.3,197.6,1c65.2,0.5,129.3,1.3,191.4,1.8
|
||||
c15.5,0,31,0.3,46,0.3h5.2l5.7,0.3c1.6,0.3,2.8,0.5,4.4,0.8c1.6,0.3,3.1,0.8,4.4,1c5.9,1.8,11.6,4.7,16.6,8.5
|
||||
c9.8,7.5,16.6,18.9,18.9,30.8c0.3,1.6,0.5,3.1,0.5,4.4c0,1.6,0.3,2.8,0.3,4.7c0,3.6,0,7.2,0,10.9c0,7.2,0,14.5,0,21.5
|
||||
c0,16,0,32.1,0.3,47.6l-49.2,28.7l-1-102.4c0-3.9-3.1-7-7-7l0,0c-17.8-0.3-35.7-0.5-53.5-0.8l-53.5-0.8l-106.8-1l-106.8-0.3
|
||||
L130.9,67H77.3l0,0c-5.4,0-9.8,4.4-9.8,10.1l0.3,104.3v52l0.3,52l0.8,104.3c0.5,34.7,0.8,69.6,1.3,104.3l0,0c0,3.9,3.1,7,7,7
|
||||
l320.8,3.6l53.5,0.5l26.6,0.3c8.8,0,17.8,0,26.6,0h0.3l0,0c6.2,0,11.1-5.2,11.1-11.4l-2.3-214.2l48.6-28.5
|
||||
C563.4,255.3,563.4,259.5,563.7,263.6z M256.6,331.1c-8.5-11.1-17.1-22.2-25.6-33.1l-29.5-38l-7.5-9.3c-0.8-0.8-1-1.6-2.1-2.3
|
||||
c-0.8-1-1.6-1.8-2.6-2.8l-2.8-2.6c-1-0.8-2.1-1.6-3.1-2.3c-8.5-5.9-19.1-8.8-29.2-7.5c-5.2,0.5-10.3,2.1-15,4.4
|
||||
c-1.3,0.8-2.6,1.3-3.9,2.1c-0.8,0.5-1,0.5-1.3,1l-1.3,0.8l-0.5,0.5l-0.5,0.5l-0.3,0.3l-0.3,0.3l-1.6,1.3c-1,0.8-1.8,1.8-2.8,2.8
|
||||
c-7.2,7.8-11.4,17.8-11.6,28.5c0,5.2,0.8,10.6,2.3,15.5c0.3,1.3,1,2.6,1.6,3.6l0.8,1.8l1,1.8l1,1.8c0.5,0.8,0.5,0.8,1,1.3l0.8,1.3
|
||||
l0.3,0.3v0.3l0.5,0.5l0.5,0.5l15,18.9l30,37.5l30,37.5l7.5,9.3l3.9,4.7c1.6,1.8,3.4,3.9,5.4,5.7c4.1,3.6,8.8,6.5,13.7,8.3
|
||||
c2.6,1,5.2,1.6,7.8,2.1c1.3,0.3,2.6,0.5,4.1,0.5h1c0.5,0,0.8,0,1,0h1.6h0.3c7.5,0,15.3-2.1,21.7-5.7l14.7-8.5l29.2-17.1l58.7-34.1
|
||||
l117.4-68.3l7.5-4.4l-2.1,192.2c-5.2,0-10.3,0-15.5,0l-26.6,0.3l-53.5,0.5L291,484.8l-206.7,2.3c0.5-32.3,0.8-64.7,1.3-97l0.8-104.3
|
||||
l0.3-52v-52l0.3-94.2h43.5l53.5-0.3l106.8-0.3l106.8-1l53.5-0.8c15.5-0.3,30.8-0.5,46.3-0.8l-1,105l-12.4,7.2l-116.9,69.1
|
||||
L256.6,331.1z M698.7,138.7c-0.8,3.9-2.3,7.5-4.9,10.6c-1.3,1.6-2.6,2.8-4.1,3.9c-0.8,0.5-1.6,1-2.6,1.6l-3.6,2.1L654,173.6
|
||||
l-58.7,33.9l-117.4,68.3l-117.4,68l-58.7,33.9l-29.5,17.1l-14.5,8.3c-3.4,1.8-7,2.8-10.6,2.8h-1.3c-0.3,0-0.5,0-0.5,0H245
|
||||
c-0.5,0-1.3-0.3-1.8-0.3c-1.3-0.3-2.6-0.5-3.9-1c-2.6-0.8-4.7-2.3-6.7-3.9c-1-1-1.8-1.8-2.8-2.8l-3.9-4.7l-7.5-9.3l-30.3-37.3
|
||||
l-30.8-37.5L142,290.5l-0.5-0.5l-0.3-0.3l-0.8-1.3c-0.3-0.3-0.8-0.8-0.8-1l-0.3-0.8l-0.5-0.8l-0.5-1c-0.3-0.5-0.5-1.3-0.8-1.8
|
||||
c-1-2.6-1.6-5.2-1.6-8c0-5.4,2.1-11.1,5.7-15.3c0.5-0.5,1-1,1.6-1.6l0.8-0.8l0.3-0.3l0,0l0,0l0.3-0.3l1.3-0.8c0.3-0.3,0.8-0.8,1-0.8
|
||||
c0.5-0.3,1-0.5,1.6-0.8c2.6-1.3,5.2-2.1,8-2.6c5.7-0.8,11.6,0.5,16.3,3.9c0.5,0.5,1.3,0.8,1.8,1.3l1.6,1.3l1.6,1.6
|
||||
c0.5,0.5,1.3,1.6,1.8,2.1l7.8,9.3l31,36.7c10.3,12.2,20.7,24.6,31,36.7l0,0l0,0c2.1,2.6,5.9,3.4,9.1,1.6l118-67.3l118-67.3
|
||||
l117.7-67.5l29.5-16.8l14.7-8.5l7.2-4.1l0.5-0.3l0,0l0,0l1-0.5l1.8-1c0.3,0,0.8-0.3,1-0.3c0.3-0.3,0.8-0.3,1.3-0.5
|
||||
c7.5-2.3,16.3-0.5,22,4.9c2.8,2.6,5.2,5.9,6.5,9.8C699,130.6,699.2,134.8,698.7,138.7z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
6342
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 03.dxf
Normal file
6342
Printing/Nameplates/Check-Mark/CF00089-08 Check Mark 03.dxf
Normal file
File diff suppressed because it is too large
Load Diff
27
Printing/Nameplates/Check-Mark/index.html
Normal file
27
Printing/Nameplates/Check-Mark/index.html
Normal file
@@ -0,0 +1,27 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Directory listing for /Printing/Nameplates/Check-Mark/</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Directory listing for /Printing/Nameplates/Check-Mark/</h1>
|
||||
<hr>
|
||||
<ul>
|
||||
<li><a href="CF00089-08%20Check%20Mark%2001.dxf">CF00089-08 Check Mark 01.dxf</a></li>
|
||||
<li><a href="CF00089-08%20Check%20Mark%2001.eps">CF00089-08 Check Mark 01.eps</a></li>
|
||||
<li><a href="CF00089-08%20Check%20Mark%2001.png">CF00089-08 Check Mark 01.png</a></li>
|
||||
<li><a href="CF00089-08%20Check%20Mark%2001.svg">CF00089-08 Check Mark 01.svg</a></li>
|
||||
<li><a href="CF00089-08%20Check%20Mark%2002.dxf">CF00089-08 Check Mark 02.dxf</a></li>
|
||||
<li><a href="CF00089-08%20Check%20Mark%2002.eps">CF00089-08 Check Mark 02.eps</a></li>
|
||||
<li><a href="CF00089-08%20Check%20Mark%2002.png">CF00089-08 Check Mark 02.png</a></li>
|
||||
<li><a href="CF00089-08%20Check%20Mark%2002.svg">CF00089-08 Check Mark 02.svg</a></li>
|
||||
<li><a href="CF00089-08%20Check%20Mark%2003.dxf">CF00089-08 Check Mark 03.dxf</a></li>
|
||||
<li><a href="CF00089-08%20Check%20Mark%2003.eps">CF00089-08 Check Mark 03.eps</a></li>
|
||||
<li><a href="CF00089-08%20Check%20Mark%2003.png">CF00089-08 Check Mark 03.png</a></li>
|
||||
<li><a href="CF00089-08%20Check%20Mark%2003.svg">CF00089-08 Check Mark 03.svg</a></li>
|
||||
<li><a href="Note.txt">Note.txt</a></li>
|
||||
</ul>
|
||||
<hr>
|
||||
</body>
|
||||
</html>
|
||||
BIN
Printing/Nameplates/Fordscript.ttf
Normal file
BIN
Printing/Nameplates/Fordscript.ttf
Normal file
Binary file not shown.
BIN
Printing/Nameplates/Screenshot 2025-11-07 082805.png
Normal file
BIN
Printing/Nameplates/Screenshot 2025-11-07 082805.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 85 KiB |
174
Printing/Nameplates/add_filament_change_to_3mf.py
Normal file
174
Printing/Nameplates/add_filament_change_to_3mf.py
Normal file
@@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Add M600 filament change command to all objects in an Orca Slicer 3MF file.
|
||||
|
||||
This script modifies a 3MF file (which is a ZIP archive containing XML) to add
|
||||
a height range modifier at 1.5mm (end of blue base layer) with M600 command
|
||||
for all zipper pull objects.
|
||||
|
||||
Usage:
|
||||
python add_filament_change_to_3mf.py input.3mf [output.3mf]
|
||||
|
||||
If output.3mf is not specified, creates input_modified.3mf
|
||||
"""
|
||||
|
||||
import sys
|
||||
import zipfile
|
||||
import xml.etree.ElementTree as ET
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
|
||||
def add_height_range_to_3mf(input_file, output_file=None, height_mm=1.5):
|
||||
"""
|
||||
Add height range modifier with M600 at specified height to all objects in 3MF.
|
||||
|
||||
Args:
|
||||
input_file: Path to input 3MF file
|
||||
output_file: Path to output 3MF file (optional)
|
||||
height_mm: Height in mm where filament change occurs (default: 1.5)
|
||||
"""
|
||||
input_path = Path(input_file)
|
||||
|
||||
if not input_path.exists():
|
||||
print(f"Error: Input file '{input_file}' not found!")
|
||||
return False
|
||||
|
||||
# Determine output filename
|
||||
if output_file is None:
|
||||
output_path = input_path.parent / f"{input_path.stem}_modified.3mf"
|
||||
else:
|
||||
output_path = Path(output_file)
|
||||
|
||||
print(f"Processing: {input_path}")
|
||||
print(f"Output will be: {output_path}")
|
||||
print(f"Filament change height: {height_mm}mm")
|
||||
print("-" * 50)
|
||||
|
||||
# Create a temporary directory to work in
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
temp_path = Path(temp_dir)
|
||||
|
||||
# Extract the 3MF (it's a ZIP file)
|
||||
print("Extracting 3MF file...")
|
||||
with zipfile.ZipFile(input_path, 'r') as zip_ref:
|
||||
zip_ref.extractall(temp_path)
|
||||
|
||||
# Find and modify the 3D model file (usually 3D/3dmodel.model)
|
||||
model_file = temp_path / "3D" / "3dmodel.model"
|
||||
|
||||
if not model_file.exists():
|
||||
print("Error: Could not find 3dmodel.model in 3MF file!")
|
||||
return False
|
||||
|
||||
print(f"Modifying {model_file}...")
|
||||
|
||||
# Parse the XML
|
||||
tree = ET.parse(model_file)
|
||||
root = tree.getroot()
|
||||
|
||||
# Define namespaces (3MF uses namespaces)
|
||||
namespaces = {
|
||||
'': 'http://schemas.microsoft.com/3dmanufacturing/core/2015/02',
|
||||
'p': 'http://schemas.microsoft.com/3dmanufacturing/production/2015/06',
|
||||
's': 'http://schemas.orca-3d.com/3mf/2023/06'
|
||||
}
|
||||
|
||||
# Register namespaces for output
|
||||
for prefix, uri in namespaces.items():
|
||||
if prefix:
|
||||
ET.register_namespace(prefix, uri)
|
||||
else:
|
||||
ET.register_namespace('', uri)
|
||||
|
||||
# Find all objects (build items)
|
||||
# In Orca Slicer 3MF, objects are in <build><item> tags
|
||||
build_elem = root.find('.//build', namespaces)
|
||||
|
||||
if build_elem is None:
|
||||
print("Warning: No <build> element found. Looking for items directly...")
|
||||
items = root.findall('.//item', namespaces)
|
||||
else:
|
||||
items = build_elem.findall('.//item', namespaces)
|
||||
|
||||
if not items:
|
||||
print("Error: No items found in 3MF file!")
|
||||
return False
|
||||
|
||||
print(f"Found {len(items)} object(s) in the file")
|
||||
|
||||
# Count modified items
|
||||
modified_count = 0
|
||||
|
||||
# Add height range modifier to each item
|
||||
for idx, item in enumerate(items, 1):
|
||||
object_id = item.get('objectid', f'unknown_{idx}')
|
||||
print(f" Processing object {idx}/{len(items)} (ID: {object_id})...")
|
||||
|
||||
# Check if this item already has metadata for height range
|
||||
# In Orca Slicer, this is typically stored as metadata
|
||||
# We need to add the height range modifier metadata
|
||||
|
||||
# Note: The exact XML structure for height range modifiers in Orca Slicer
|
||||
# may vary. This is a generic approach that adds metadata.
|
||||
# You may need to adjust based on actual Orca Slicer 3MF structure.
|
||||
|
||||
# Create or find metadata container
|
||||
metadata_group = item.find('metadatagroup', namespaces)
|
||||
if metadata_group is None:
|
||||
metadata_group = ET.SubElement(item, 'metadatagroup')
|
||||
|
||||
# Add height range modifier metadata
|
||||
# Format: height range from 0 to height_mm = blue (original)
|
||||
# height range from height_mm to top = white (with M600)
|
||||
|
||||
height_modifier = ET.SubElement(metadata_group, 'metadata')
|
||||
height_modifier.set('name', 'height_range_modifier')
|
||||
height_modifier.text = f'{{"ranges":[{{"min":0,"max":{height_mm},"color":"RoyalBlue"}},{{"min":{height_mm},"max":999,"color":"white","gcode":"M600"}}]}}'
|
||||
|
||||
modified_count += 1
|
||||
|
||||
print(f"\nModified {modified_count} object(s)")
|
||||
|
||||
# Save the modified XML back to the file
|
||||
print("Saving modified model file...")
|
||||
tree.write(model_file, encoding='utf-8', xml_declaration=True)
|
||||
|
||||
# Re-create the 3MF (ZIP) file with all contents
|
||||
print("Creating new 3MF file...")
|
||||
with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as zip_out:
|
||||
# Walk through the temp directory and add all files
|
||||
for root_dir, dirs, files in os.walk(temp_path):
|
||||
for file in files:
|
||||
file_path = Path(root_dir) / file
|
||||
arcname = file_path.relative_to(temp_path)
|
||||
zip_out.write(file_path, arcname)
|
||||
|
||||
print(f"\nSuccess! Modified 3MF saved to: {output_path}")
|
||||
print(f"\nNext steps:")
|
||||
print(f"1. Open {output_path.name} in Orca Slicer")
|
||||
print(f"2. Verify the height range modifiers are present")
|
||||
print(f"3. Slice and check for M600 commands in the G-code")
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python add_filament_change_to_3mf.py input.3mf [output.3mf]")
|
||||
print("\nAdds M600 filament change at 1.5mm to all objects in a 3MF file.")
|
||||
print("If output.3mf is not specified, creates input_modified.3mf")
|
||||
sys.exit(1)
|
||||
|
||||
input_file = sys.argv[1]
|
||||
output_file = sys.argv[2] if len(sys.argv) > 2 else None
|
||||
|
||||
success = add_height_range_to_3mf(input_file, output_file)
|
||||
|
||||
if not success:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
179
Printing/Nameplates/add_height_modifier_orca.py
Normal file
179
Printing/Nameplates/add_height_modifier_orca.py
Normal file
@@ -0,0 +1,179 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Add M600 filament change to Orca Slicer 3MF file.
|
||||
|
||||
Based on actual Orca Slicer format analysis.
|
||||
Adds global height_range_modifier metadata that applies to all objects.
|
||||
|
||||
Usage:
|
||||
python add_height_modifier_orca.py input.3mf [output.3mf]
|
||||
"""
|
||||
|
||||
import sys
|
||||
import zipfile
|
||||
import xml.etree.ElementTree as ET
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
|
||||
def add_height_modifier(input_file, output_file=None, height_mm=1.5):
|
||||
"""
|
||||
Add height range modifier metadata to 3MF file.
|
||||
|
||||
Args:
|
||||
input_file: Path to input 3MF file
|
||||
output_file: Path to output 3MF file (optional)
|
||||
height_mm: Height in mm where filament change occurs
|
||||
"""
|
||||
input_path = Path(input_file)
|
||||
|
||||
if not input_path.exists():
|
||||
print(f"Error: Input file '{input_file}' not found!")
|
||||
return False
|
||||
|
||||
if output_file is None:
|
||||
output_path = input_path.parent / f"{input_path.stem}_modified.3mf"
|
||||
else:
|
||||
output_path = Path(output_file)
|
||||
|
||||
print(f"Processing: {input_path}")
|
||||
print(f"Output: {output_path}")
|
||||
print(f"Filament change at: {height_mm}mm")
|
||||
print("-" * 60)
|
||||
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
temp_path = Path(temp_dir)
|
||||
|
||||
# Extract 3MF
|
||||
print("Extracting 3MF...")
|
||||
with zipfile.ZipFile(input_path, 'r') as zip_ref:
|
||||
zip_ref.extractall(temp_path)
|
||||
|
||||
# Find model file
|
||||
model_file = temp_path / "3D" / "3dmodel.model"
|
||||
if not model_file.exists():
|
||||
print("Error: Could not find 3dmodel.model!")
|
||||
return False
|
||||
|
||||
print("Modifying model file...")
|
||||
|
||||
# Parse XML
|
||||
tree = ET.parse(model_file)
|
||||
root = tree.getroot()
|
||||
|
||||
# Register namespaces
|
||||
namespaces = {
|
||||
'': 'http://schemas.microsoft.com/3dmanufacturing/core/2015/02',
|
||||
'BambuStudio': 'http://schemas.bambulab.com/package/2021',
|
||||
'p': 'http://schemas.microsoft.com/3dmanufacturing/production/2015/06'
|
||||
}
|
||||
|
||||
for prefix, uri in namespaces.items():
|
||||
if prefix:
|
||||
ET.register_namespace(prefix, uri)
|
||||
else:
|
||||
ET.register_namespace('', uri)
|
||||
|
||||
# Find or create metadata section (should be at root level, before <resources>)
|
||||
# Check if height_range_modifier already exists
|
||||
existing_modifier = None
|
||||
for metadata in root.findall('.//metadata[@name="height_range_modifier"]', namespaces):
|
||||
existing_modifier = metadata
|
||||
break
|
||||
|
||||
if existing_modifier is not None:
|
||||
print(" Found existing height_range_modifier, replacing...")
|
||||
root.remove(existing_modifier)
|
||||
|
||||
# Create the height range modifier metadata
|
||||
# Format: JSON string - we'll manually insert it to avoid auto-escaping
|
||||
metadata_json = (
|
||||
'{"ranges":['
|
||||
f'{{"min":0,"max":{height_mm},"color":"RoyalBlue"}},'
|
||||
f'{{"min":{height_mm},"max":999,"color":"white","gcode":"M600"}}'
|
||||
']}'
|
||||
)
|
||||
|
||||
# Create metadata element - we'll manually set the text with proper escaping
|
||||
metadata_elem = ET.Element('metadata')
|
||||
metadata_elem.set('name', 'height_range_modifier')
|
||||
# Don't use .text = ... as it will auto-escape
|
||||
# We'll replace this after writing
|
||||
|
||||
# Insert after the last existing metadata element (before <resources>)
|
||||
resources = root.find('.//resources', namespaces)
|
||||
if resources is not None:
|
||||
resources_index = list(root).index(resources)
|
||||
root.insert(resources_index, metadata_elem)
|
||||
else:
|
||||
# No resources found, just append
|
||||
root.append(metadata_elem)
|
||||
|
||||
print(f" Added height_range_modifier metadata")
|
||||
print(f" Blue layer: 0mm to {height_mm}mm")
|
||||
print(f" White layer: {height_mm}mm to top (with M600)")
|
||||
|
||||
# Save modified XML
|
||||
tree.write(model_file, encoding='utf-8', xml_declaration=True)
|
||||
|
||||
# Post-process the file to fix the escaping
|
||||
# Python's ET auto-escapes, but we need &quot; not &amp;quot;
|
||||
with open(model_file, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# Replace the empty metadata element with our properly escaped version
|
||||
escaped_json = metadata_json.replace('"', '&quot;')
|
||||
content = content.replace(
|
||||
'<metadata name="height_range_modifier" />',
|
||||
f'<metadata name="height_range_modifier">{escaped_json}</metadata>'
|
||||
)
|
||||
content = content.replace(
|
||||
'<metadata name="height_range_modifier"></metadata>',
|
||||
f'<metadata name="height_range_modifier">{escaped_json}</metadata>'
|
||||
)
|
||||
|
||||
with open(model_file, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
# Re-create 3MF file
|
||||
print("Creating modified 3MF...")
|
||||
with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as zip_out:
|
||||
for root_dir, dirs, files in os.walk(temp_path):
|
||||
for file in files:
|
||||
file_path = Path(root_dir) / file
|
||||
arcname = file_path.relative_to(temp_path)
|
||||
zip_out.write(file_path, arcname)
|
||||
|
||||
print()
|
||||
print("Success! Modified 3MF saved.")
|
||||
print()
|
||||
print("Next steps:")
|
||||
print("1. Open the modified file in Orca Slicer")
|
||||
print("2. Check if height range modifier appears")
|
||||
print("3. Slice and verify M600 in G-code")
|
||||
print()
|
||||
print("Note: This adds a GLOBAL height modifier that applies to")
|
||||
print(" all objects in the build plate.")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python add_height_modifier_orca.py input.3mf [output.3mf]")
|
||||
print()
|
||||
print("Adds M600 filament change at 1.5mm (global, applies to all objects)")
|
||||
sys.exit(1)
|
||||
|
||||
input_file = sys.argv[1]
|
||||
output_file = sys.argv[2] if len(sys.argv) > 2 else None
|
||||
|
||||
success = add_height_modifier(input_file, output_file)
|
||||
|
||||
if not success:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
56
Printing/Nameplates/checkmark_template.scad
Normal file
56
Printing/Nameplates/checkmark_template.scad
Normal file
@@ -0,0 +1,56 @@
|
||||
// Two-Layer Check Mark Design
|
||||
// Black base (box + check mark) + White fill layer on top
|
||||
// Based on CF00089-08 Check Mark 01.svg
|
||||
|
||||
// Parameters - adjust these to customize
|
||||
black_base_thickness = 0.5; // Black base layer (thin, bottom)
|
||||
white_fill_thickness = 1.5; // White fill layer (middle)
|
||||
black_top_thickness = 0.5; // Black top (check mark shows through)
|
||||
desired_size = 14; // Desired box size (mm) - makes design square
|
||||
|
||||
// SVG file path
|
||||
svg_file = "Check-Mark/CF00089-08 Check Mark 01.svg";
|
||||
|
||||
// Calculate dimensions from SVG viewBox (720 x 570.9)
|
||||
svg_width = 720;
|
||||
svg_height = 570.9;
|
||||
|
||||
// Scale factors to make the design exactly square
|
||||
scale_x = desired_size / svg_width; // Scale for width
|
||||
scale_y = desired_size / svg_height; // Scale for height
|
||||
design_width = desired_size;
|
||||
design_height = desired_size;
|
||||
|
||||
// White fill inset (how much smaller than the outer box)
|
||||
white_inset = 1.5; // mm inset from edges (adjusted for 14mm box)
|
||||
white_width = design_width - (white_inset * 2);
|
||||
white_height = design_height - (white_inset * 2);
|
||||
|
||||
// Total thickness
|
||||
total_thickness = black_base_thickness + white_fill_thickness + black_top_thickness;
|
||||
|
||||
echo(str("Design size: ", design_width, "mm x ", design_height, "mm"));
|
||||
echo(str("White fill size: ", white_width, "mm x ", white_height, "mm"));
|
||||
echo(str("Total thickness: ", total_thickness, "mm"));
|
||||
|
||||
// Build the two-layer design
|
||||
module checkmark_design() {
|
||||
// Layer 1: Black base - full SVG design (box + check mark)
|
||||
color("black")
|
||||
translate([0, 0, 0])
|
||||
linear_extrude(height = total_thickness)
|
||||
// Center the SVG design
|
||||
translate([-design_width/2, -design_height/2, 0])
|
||||
scale([scale_x, scale_y, 1])
|
||||
import(svg_file, center = false);
|
||||
|
||||
// Layer 2: White fill - sits on top of black base, inside the box
|
||||
color("white")
|
||||
translate([0, 0, black_base_thickness])
|
||||
linear_extrude(height = white_fill_thickness)
|
||||
offset(r = 1) // Slightly round the corners
|
||||
square([white_width, white_height], center = true);
|
||||
}
|
||||
|
||||
// Render the complete design
|
||||
checkmark_design();
|
||||
BIN
Printing/Nameplates/fred_bennett_facedown.3mf
Normal file
BIN
Printing/Nameplates/fred_bennett_facedown.3mf
Normal file
Binary file not shown.
107
Printing/Nameplates/generate_nameplates.py
Normal file
107
Printing/Nameplates/generate_nameplates.py
Normal file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate 3D nameplate STL files from a list of names using OpenSCAD.
|
||||
|
||||
This script reads names from a text file and generates individual STL files
|
||||
for each name using an OpenSCAD template.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def generate_stl(name, template_file, output_dir):
|
||||
"""
|
||||
Generate an STL file for a given name using OpenSCAD.
|
||||
|
||||
Args:
|
||||
name: The name to put on the nameplate
|
||||
template_file: Path to the OpenSCAD template file
|
||||
output_dir: Directory where STL files will be saved
|
||||
"""
|
||||
# Create a safe filename from the name (remove special characters)
|
||||
safe_name = "".join(c for c in name if c.isalnum() or c in (' ', '-', '_')).strip()
|
||||
safe_name = safe_name.replace(' ', '_')
|
||||
|
||||
output_file = os.path.join(output_dir, f"{safe_name}.stl")
|
||||
|
||||
# Escape quotes in the name for the command line
|
||||
escaped_name = name.replace('"', '\\"')
|
||||
|
||||
# Build the OpenSCAD command
|
||||
# -D sets a variable, -o specifies output file
|
||||
cmd = [
|
||||
r'C:\Program Files\OpenSCAD\openscad.exe',
|
||||
'-D', f'name="{escaped_name}"',
|
||||
'-o', output_file,
|
||||
template_file
|
||||
]
|
||||
|
||||
print(f"Generating: {safe_name}.stl for '{name}'...")
|
||||
|
||||
try:
|
||||
# Run OpenSCAD
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
)
|
||||
print(f" [OK] Successfully created {safe_name}.stl")
|
||||
return True
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f" [ERROR] Error generating {safe_name}.stl")
|
||||
print(f" {e.stderr}")
|
||||
return False
|
||||
except FileNotFoundError:
|
||||
print("Error: OpenSCAD not found. Please install OpenSCAD and ensure it's in your PATH.")
|
||||
print("Download from: https://openscad.org/downloads.html")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
# Configuration
|
||||
template_file = "nameplate_template.scad"
|
||||
names_file = "names.txt"
|
||||
output_dir = "output_stl"
|
||||
|
||||
# Check if template exists
|
||||
if not os.path.exists(template_file):
|
||||
print(f"Error: Template file '{template_file}' not found!")
|
||||
sys.exit(1)
|
||||
|
||||
# Check if names file exists
|
||||
if not os.path.exists(names_file):
|
||||
print(f"Error: Names file '{names_file}' not found!")
|
||||
sys.exit(1)
|
||||
|
||||
# Create output directory if it doesn't exist
|
||||
Path(output_dir).mkdir(exist_ok=True)
|
||||
|
||||
# Read names from file
|
||||
with open(names_file, 'r', encoding='utf-8') as f:
|
||||
names = [line.strip() for line in f if line.strip()]
|
||||
|
||||
if not names:
|
||||
print(f"Error: No names found in '{names_file}'")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Found {len(names)} name(s) to process")
|
||||
print(f"Output directory: {output_dir}")
|
||||
print("-" * 50)
|
||||
|
||||
# Generate STL for each name
|
||||
success_count = 0
|
||||
for name in names:
|
||||
if generate_stl(name, template_file, output_dir):
|
||||
success_count += 1
|
||||
|
||||
print("-" * 50)
|
||||
print(f"Complete! Generated {success_count}/{len(names)} STL files")
|
||||
print(f"Files saved in: {output_dir}/")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
107
Printing/Nameplates/generate_zipper_pulls.py
Normal file
107
Printing/Nameplates/generate_zipper_pulls.py
Normal file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate 3D zipper pull STL files from a list of names using OpenSCAD.
|
||||
|
||||
This script reads names from a text file and generates individual STL files
|
||||
for each name using the zipper pull OpenSCAD template.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def generate_stl(name, template_file, output_dir):
|
||||
"""
|
||||
Generate an STL file for a given name using OpenSCAD.
|
||||
|
||||
Args:
|
||||
name: The name to put on the zipper pull
|
||||
template_file: Path to the OpenSCAD template file
|
||||
output_dir: Directory where STL files will be saved
|
||||
"""
|
||||
# Create a safe filename from the name (remove special characters)
|
||||
safe_name = "".join(c for c in name if c.isalnum() or c in (' ', '-', '_')).strip()
|
||||
safe_name = safe_name.replace(' ', '_')
|
||||
|
||||
output_file = os.path.join(output_dir, f"{safe_name}.stl")
|
||||
|
||||
# Escape quotes in the name for the command line
|
||||
escaped_name = name.replace('"', '\\"')
|
||||
|
||||
# Build the OpenSCAD command
|
||||
# -D sets a variable, -o specifies output file
|
||||
cmd = [
|
||||
r'C:\Program Files\OpenSCAD\openscad.exe',
|
||||
'-D', f'name="{escaped_name}"',
|
||||
'-o', output_file,
|
||||
template_file
|
||||
]
|
||||
|
||||
print(f"Generating: {safe_name}.stl for '{name}'...")
|
||||
|
||||
try:
|
||||
# Run OpenSCAD
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
)
|
||||
print(f" [OK] Successfully created {safe_name}.stl")
|
||||
return True
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f" [ERROR] Error generating {safe_name}.stl")
|
||||
print(f" {e.stderr}")
|
||||
return False
|
||||
except FileNotFoundError:
|
||||
print("Error: OpenSCAD not found. Please install OpenSCAD and ensure it's in your PATH.")
|
||||
print("Download from: https://openscad.org/downloads.html")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
# Configuration
|
||||
template_file = "zipper_pull_template.scad"
|
||||
names_file = "names.txt"
|
||||
output_dir = "zipper-pulls"
|
||||
|
||||
# Check if template exists
|
||||
if not os.path.exists(template_file):
|
||||
print(f"Error: Template file '{template_file}' not found!")
|
||||
sys.exit(1)
|
||||
|
||||
# Check if names file exists
|
||||
if not os.path.exists(names_file):
|
||||
print(f"Error: Names file '{names_file}' not found!")
|
||||
sys.exit(1)
|
||||
|
||||
# Create output directory if it doesn't exist
|
||||
Path(output_dir).mkdir(exist_ok=True)
|
||||
|
||||
# Read names from file
|
||||
with open(names_file, 'r', encoding='utf-8') as f:
|
||||
names = [line.strip() for line in f if line.strip()]
|
||||
|
||||
if not names:
|
||||
print(f"Error: No names found in '{names_file}'")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Found {len(names)} name(s) to process")
|
||||
print(f"Output directory: {output_dir}")
|
||||
print("-" * 50)
|
||||
|
||||
# Generate STL for each name
|
||||
success_count = 0
|
||||
for name in names:
|
||||
if generate_stl(name, template_file, output_dir):
|
||||
success_count += 1
|
||||
|
||||
print("-" * 50)
|
||||
print(f"Complete! Generated {success_count}/{len(names)} STL files")
|
||||
print(f"Files saved in: {output_dir}/")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
107
Printing/Nameplates/generate_zipper_pulls_raised_text.py
Normal file
107
Printing/Nameplates/generate_zipper_pulls_raised_text.py
Normal file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate 3D zipper pull STL files with raised text from a list of names using OpenSCAD.
|
||||
|
||||
This script reads names from a text file and generates individual STL files
|
||||
for each name using the raised text zipper pull OpenSCAD template.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def generate_stl(name, template_file, output_dir):
|
||||
"""
|
||||
Generate an STL file for a given name using OpenSCAD.
|
||||
|
||||
Args:
|
||||
name: The name to put on the zipper pull
|
||||
template_file: Path to the OpenSCAD template file
|
||||
output_dir: Directory where STL files will be saved
|
||||
"""
|
||||
# Create a safe filename from the name (remove special characters)
|
||||
safe_name = "".join(c for c in name if c.isalnum() or c in (' ', '-', '_')).strip()
|
||||
safe_name = safe_name.replace(' ', '_')
|
||||
|
||||
output_file = os.path.join(output_dir, f"{safe_name}.stl")
|
||||
|
||||
# Escape quotes in the name for the command line
|
||||
escaped_name = name.replace('"', '\\"')
|
||||
|
||||
# Build the OpenSCAD command
|
||||
# -D sets a variable, -o specifies output file
|
||||
cmd = [
|
||||
r'C:\Program Files\OpenSCAD\openscad.exe',
|
||||
'-D', f'name="{escaped_name}"',
|
||||
'-o', output_file,
|
||||
template_file
|
||||
]
|
||||
|
||||
print(f"Generating: {safe_name}.stl for '{name}'...")
|
||||
|
||||
try:
|
||||
# Run OpenSCAD
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
)
|
||||
print(f" [OK] Successfully created {safe_name}.stl")
|
||||
return True
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f" [ERROR] Error generating {safe_name}.stl")
|
||||
print(f" {e.stderr}")
|
||||
return False
|
||||
except FileNotFoundError:
|
||||
print("Error: OpenSCAD not found. Please install OpenSCAD and ensure it's in your PATH.")
|
||||
print("Download from: https://openscad.org/downloads.html")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
# Configuration
|
||||
template_file = "zipper_pull_raised_text_template.scad"
|
||||
names_file = "names.txt"
|
||||
output_dir = "zipper-pulls-raised-text"
|
||||
|
||||
# Check if template exists
|
||||
if not os.path.exists(template_file):
|
||||
print(f"Error: Template file '{template_file}' not found!")
|
||||
sys.exit(1)
|
||||
|
||||
# Check if names file exists
|
||||
if not os.path.exists(names_file):
|
||||
print(f"Error: Names file '{names_file}' not found!")
|
||||
sys.exit(1)
|
||||
|
||||
# Create output directory if it doesn't exist
|
||||
Path(output_dir).mkdir(exist_ok=True)
|
||||
|
||||
# Read names from file
|
||||
with open(names_file, 'r', encoding='utf-8') as f:
|
||||
names = [line.strip() for line in f if line.strip()]
|
||||
|
||||
if not names:
|
||||
print(f"Error: No names found in '{names_file}'")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Found {len(names)} name(s) to process")
|
||||
print(f"Output directory: {output_dir}")
|
||||
print("-" * 50)
|
||||
|
||||
# Generate STL for each name
|
||||
success_count = 0
|
||||
for name in names:
|
||||
if generate_stl(name, template_file, output_dir):
|
||||
success_count += 1
|
||||
|
||||
print("-" * 50)
|
||||
print(f"Complete! Generated {success_count}/{len(names)} STL files")
|
||||
print(f"Files saved in: {output_dir}/")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
113
Printing/Nameplates/generate_zipper_pulls_raised_text_2.py
Normal file
113
Printing/Nameplates/generate_zipper_pulls_raised_text_2.py
Normal file
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate 3D zipper pull STL files with raised text from a list of names using OpenSCAD.
|
||||
|
||||
This script reads names from a text file and generates individual STL files
|
||||
for each name using the raised text zipper pull OpenSCAD template.
|
||||
|
||||
Version 2: Improved apostrophe handling - preserves apostrophes in both filenames and text rendering.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def generate_stl(name, template_file, output_dir):
|
||||
"""
|
||||
Generate an STL file for a given name using OpenSCAD.
|
||||
|
||||
Args:
|
||||
name: The name to put on the zipper pull
|
||||
template_file: Path to the OpenSCAD template file
|
||||
output_dir: Directory where STL files will be saved
|
||||
"""
|
||||
# Create a safe filename from the name
|
||||
# Keep apostrophes in filename for accurate representation
|
||||
safe_name = "".join(c for c in name if c.isalnum() or c in (' ', '-', '_', "\'")).strip()
|
||||
safe_name = safe_name.replace(' ', '_')
|
||||
|
||||
output_file = os.path.join(output_dir, f"{safe_name}.stl")
|
||||
|
||||
# Escape the name for OpenSCAD command line
|
||||
# Need to escape both quotes and apostrophes properly
|
||||
escaped_name = name.replace('\\', '\\\\') # Escape backslashes first
|
||||
escaped_name = escaped_name.replace('"', '\\"') # Escape double quotes
|
||||
escaped_name = escaped_name.replace("'", "\\'") # Escape single quotes/apostrophes
|
||||
|
||||
# Build the OpenSCAD command
|
||||
# -D sets a variable, -o specifies output file
|
||||
cmd = [
|
||||
r'C:\Program Files\OpenSCAD\openscad.exe',
|
||||
'-D', f'name="{escaped_name}"',
|
||||
'-o', output_file,
|
||||
template_file
|
||||
]
|
||||
|
||||
print(f"Generating: {safe_name}.stl for '{name}'...")
|
||||
|
||||
try:
|
||||
# Run OpenSCAD
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
)
|
||||
print(f" [OK] Successfully created {safe_name}.stl")
|
||||
return True
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f" [ERROR] Error generating {safe_name}.stl")
|
||||
print(f" {e.stderr}")
|
||||
return False
|
||||
except FileNotFoundError:
|
||||
print("Error: OpenSCAD not found. Please install OpenSCAD and ensure it's in your PATH.")
|
||||
print("Download from: https://openscad.org/downloads.html")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
# Configuration
|
||||
template_file = "zipper_pull_raised_text_template.scad"
|
||||
names_file = "names.txt"
|
||||
output_dir = "zipper-pulls-raised-text-2"
|
||||
|
||||
# Check if template exists
|
||||
if not os.path.exists(template_file):
|
||||
print(f"Error: Template file '{template_file}' not found!")
|
||||
sys.exit(1)
|
||||
|
||||
# Check if names file exists
|
||||
if not os.path.exists(names_file):
|
||||
print(f"Error: Names file '{names_file}' not found!")
|
||||
sys.exit(1)
|
||||
|
||||
# Create output directory if it doesn't exist
|
||||
Path(output_dir).mkdir(exist_ok=True)
|
||||
|
||||
# Read names from file
|
||||
with open(names_file, 'r', encoding='utf-8') as f:
|
||||
names = [line.strip() for line in f if line.strip()]
|
||||
|
||||
if not names:
|
||||
print(f"Error: No names found in '{names_file}'")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Found {len(names)} name(s) to process")
|
||||
print(f"Output directory: {output_dir}")
|
||||
print("-" * 50)
|
||||
|
||||
# Generate STL for each name
|
||||
success_count = 0
|
||||
for name in names:
|
||||
if generate_stl(name, template_file, output_dir):
|
||||
success_count += 1
|
||||
|
||||
print("-" * 50)
|
||||
print(f"Complete! Generated {success_count}/{len(names)} STL files")
|
||||
print(f"Files saved in: {output_dir}/")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
61
Printing/Nameplates/index.html
Normal file
61
Printing/Nameplates/index.html
Normal file
@@ -0,0 +1,61 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Directory listing for /Printing/Nameplates/</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Directory listing for /Printing/Nameplates/</h1>
|
||||
<hr>
|
||||
<ul>
|
||||
<li><a href=".claude/">.claude/</a></li>
|
||||
<li><a href=".github/">.github/</a></li>
|
||||
<li><a href="300.103.pdf">300.103.pdf</a></li>
|
||||
<li><a href="add_filament_change_to_3mf.py">add_filament_change_to_3mf.py</a></li>
|
||||
<li><a href="add_height_modifier_orca.py">add_height_modifier_orca.py</a></li>
|
||||
<li><a href="Check-Mark/">Check-Mark/</a></li>
|
||||
<li><a href="checkmark_template.scad">checkmark_template.scad</a></li>
|
||||
<li><a href="CLAUDE.md">CLAUDE.md</a></li>
|
||||
<li><a href="Fordscript.ttf">Fordscript.ttf</a></li>
|
||||
<li><a href="fred_bennett_facedown.3mf">fred_bennett_facedown.3mf</a></li>
|
||||
<li><a href="generate_nameplates.py">generate_nameplates.py</a></li>
|
||||
<li><a href="generate_zipper_pulls.py">generate_zipper_pulls.py</a></li>
|
||||
<li><a href="generate_zipper_pulls_raised_text.py">generate_zipper_pulls_raised_text.py</a></li>
|
||||
<li><a href="generate_zipper_pulls_raised_text_2.py">generate_zipper_pulls_raised_text_2.py</a></li>
|
||||
<li><a href="nameplate_template.scad">nameplate_template.scad</a></li>
|
||||
<li><a href="names.txt">names.txt</a></li>
|
||||
<li><a href="nul">nul</a></li>
|
||||
<li><a href="output_stl/">output_stl/</a></li>
|
||||
<li><a href="Screenshot%202025-11-07%20082805.png">Screenshot 2025-11-07 082805.png</a></li>
|
||||
<li><a href="test_bennet_facedown.stl">test_bennet_facedown.stl</a></li>
|
||||
<li><a href="test_bennett_facedown.3mf">test_bennett_facedown.3mf</a></li>
|
||||
<li><a href="test_blue_only.3mf">test_blue_only.3mf</a></li>
|
||||
<li><a href="test_blue_only.scad">test_blue_only.scad</a></li>
|
||||
<li><a href="test_christopher.stl">test_christopher.stl</a></li>
|
||||
<li><a href="test_christopher_13pt.stl">test_christopher_13pt.stl</a></li>
|
||||
<li><a href="test_christopher_dynamic.stl">test_christopher_dynamic.stl</a></li>
|
||||
<li><a href="test_christopher_raised.stl">test_christopher_raised.stl</a></li>
|
||||
<li><a href="test_debug.3mf">test_debug.3mf</a></li>
|
||||
<li><a href="test_debug.scad">test_debug.scad</a></li>
|
||||
<li><a href="test_font.scad">test_font.scad</a></li>
|
||||
<li><a href="test_font.stl">test_font.stl</a></li>
|
||||
<li><a href="test_fred_bold.stl">test_fred_bold.stl</a></li>
|
||||
<li><a href="test_fred_debug.stl">test_fred_debug.stl</a></li>
|
||||
<li><a href="test_fred_dynamic.stl">test_fred_dynamic.stl</a></li>
|
||||
<li><a href="test_fred_raised.stl">test_fred_raised.stl</a></li>
|
||||
<li><a href="TEST_Fred_raised_text.stl">TEST_Fred_raised_text.stl</a></li>
|
||||
<li><a href="test_fred_reduced_bold.stl">test_fred_reduced_bold.stl</a></li>
|
||||
<li><a href="test_hole_position.stl">test_hole_position.stl</a></li>
|
||||
<li><a href="test_simple_fred.scad">test_simple_fred.scad</a></li>
|
||||
<li><a href="test_simple_fred.stl">test_simple_fred.stl</a></li>
|
||||
<li><a href="test_zoe.stl">test_zoe.stl</a></li>
|
||||
<li><a href="test_zoe_raised.stl">test_zoe_raised.stl</a></li>
|
||||
<li><a href="zipper-pulls-raised-text/">zipper-pulls-raised-text/</a></li>
|
||||
<li><a href="zipper-pulls-raised-text-2/">zipper-pulls-raised-text-2/</a></li>
|
||||
<li><a href="zipper_pull_raised_text_template.scad">zipper_pull_raised_text_template.scad</a></li>
|
||||
<li><a href="zipper_pull_raised_text_template_REDUCED_BOLD.scad">zipper_pull_raised_text_template_REDUCED_BOLD.scad</a></li>
|
||||
<li><a href="zipper_pull_template.scad">zipper_pull_template.scad</a></li>
|
||||
</ul>
|
||||
<hr>
|
||||
</body>
|
||||
</html>
|
||||
57
Printing/Nameplates/nameplate_template.scad
Normal file
57
Printing/Nameplates/nameplate_template.scad
Normal file
@@ -0,0 +1,57 @@
|
||||
// Two-Layer Oval Nameplate Template with Engraved Text
|
||||
// Creates a white base oval with a blue top oval and engraved text
|
||||
|
||||
// Parameters - these can be overridden from command line
|
||||
name = "NAME"; // Text to display on nameplate
|
||||
oval_width = 100; // Width of the oval (mm) - max 100mm
|
||||
oval_height = 38; // Height of the oval (mm) - proportional to width
|
||||
base_thickness = 1.5; // Thickness of white base layer (mm)
|
||||
top_thickness = 1; // Thickness of blue top layer (mm)
|
||||
base_offset = 2; // How much larger the white base is (mm)
|
||||
text_size = 15; // Font size for the text
|
||||
text_depth = 1; // How deep the text is engraved (mm) - cuts through blue to show white
|
||||
font_file = "C:/Users/Fred/claude/Fordscript.ttf"; // Path to the custom font file
|
||||
|
||||
// Module to create an oval (ellipse)
|
||||
module oval(width, height, depth) {
|
||||
scale([width/2, height/2, 1])
|
||||
cylinder(h=depth, r=1, $fn=100);
|
||||
}
|
||||
|
||||
// White base layer (larger oval)
|
||||
module base_layer() {
|
||||
color("white")
|
||||
oval(
|
||||
oval_width + base_offset*2,
|
||||
oval_height + base_offset*2,
|
||||
base_thickness
|
||||
);
|
||||
}
|
||||
|
||||
// Blue top layer with engraved text
|
||||
module top_layer() {
|
||||
color("RoyalBlue")
|
||||
difference() {
|
||||
// Blue oval
|
||||
translate([0, 0, base_thickness])
|
||||
oval(oval_width, oval_height, top_thickness);
|
||||
|
||||
// Engraved text (cuts into the blue layer)
|
||||
translate([0, 0, base_thickness + top_thickness - text_depth + 0.01])
|
||||
linear_extrude(height=text_depth)
|
||||
text(name,
|
||||
size=text_size,
|
||||
font="Fordscript",
|
||||
halign="center",
|
||||
valign="center");
|
||||
}
|
||||
}
|
||||
|
||||
// Main nameplate assembly
|
||||
module nameplate() {
|
||||
base_layer();
|
||||
top_layer();
|
||||
}
|
||||
|
||||
// Generate the nameplate
|
||||
nameplate();
|
||||
58
Printing/Nameplates/names.txt
Normal file
58
Printing/Nameplates/names.txt
Normal file
@@ -0,0 +1,58 @@
|
||||
Skylar
|
||||
Aaron
|
||||
Kathrynn
|
||||
Alice
|
||||
Jaxxin
|
||||
Sydney
|
||||
Blake
|
||||
Ayden
|
||||
Bentley
|
||||
Landon
|
||||
Silas
|
||||
Aniah
|
||||
Silas
|
||||
Donald
|
||||
Hunter
|
||||
Harper
|
||||
Keith
|
||||
Karleigh
|
||||
Michael
|
||||
Taylor
|
||||
Adalynn
|
||||
Harley
|
||||
Danny
|
||||
Carson
|
||||
Aur'heir
|
||||
Kinleigh
|
||||
Bennett
|
||||
Lucy
|
||||
Grayson
|
||||
Leon
|
||||
Charlotte
|
||||
Landon
|
||||
Aiden
|
||||
Nevaeh
|
||||
Ayla
|
||||
Leah
|
||||
William
|
||||
Lane
|
||||
Liberty
|
||||
Karter
|
||||
Wyatt
|
||||
Clare
|
||||
Bryant
|
||||
Cole
|
||||
Jordan
|
||||
Max
|
||||
Zoey
|
||||
Eli
|
||||
Oliver
|
||||
Jack
|
||||
Tyler
|
||||
Annabella
|
||||
Amaya
|
||||
Shane
|
||||
Nicholas
|
||||
Clay
|
||||
Jayden
|
||||
Alexis
|
||||
15
Printing/Nameplates/output_stl/index.html
Normal file
15
Printing/Nameplates/output_stl/index.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Directory listing for /Printing/Nameplates/output_stl/</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Directory listing for /Printing/Nameplates/output_stl/</h1>
|
||||
<hr>
|
||||
<ul>
|
||||
<li><a href="2names%27.3mf">2names'.3mf</a></li>
|
||||
</ul>
|
||||
<hr>
|
||||
</body>
|
||||
</html>
|
||||
BIN
Printing/Nameplates/test_bennett_facedown.3mf
Normal file
BIN
Printing/Nameplates/test_bennett_facedown.3mf
Normal file
Binary file not shown.
BIN
Printing/Nameplates/test_blue_only.3mf
Normal file
BIN
Printing/Nameplates/test_blue_only.3mf
Normal file
Binary file not shown.
61
Printing/Nameplates/test_blue_only.scad
Normal file
61
Printing/Nameplates/test_blue_only.scad
Normal file
@@ -0,0 +1,61 @@
|
||||
// Test - only blue layer from main template
|
||||
name = "Bennett";
|
||||
oval_width = 96;
|
||||
oval_height = 30;
|
||||
blue_thickness = 1;
|
||||
white_thickness = 1.5;
|
||||
base_text_size = 13;
|
||||
|
||||
name_length = len(name);
|
||||
text_size = name_length <= 3 ? 18 :
|
||||
name_length <= 5 ? 13 :
|
||||
name_length <= 8 ? 11 :
|
||||
11;
|
||||
|
||||
border_width = 2;
|
||||
hole_diameter = 4;
|
||||
hole_clearance = 4;
|
||||
|
||||
total_width = oval_width + border_width*2;
|
||||
total_height = oval_height + border_width*2;
|
||||
hole_x = -(total_width/2) + (hole_diameter/2) + hole_clearance;
|
||||
|
||||
module oval(width, height, depth) {
|
||||
scale([width/2, height/2, 1])
|
||||
cylinder(h=depth, r=1, $fn=100);
|
||||
}
|
||||
|
||||
module bold_text() {
|
||||
for (x = [-0.3, 0, 0.3]) {
|
||||
for (y = [-0.3, 0, 0.3]) {
|
||||
translate([x, y, 0])
|
||||
linear_extrude(height=blue_thickness + 0.1)
|
||||
text(name,
|
||||
size=text_size,
|
||||
font="Fordscript",
|
||||
halign="center",
|
||||
valign="center");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Blue layer only
|
||||
color("RoyalBlue")
|
||||
difference() {
|
||||
oval(total_width, total_height, blue_thickness);
|
||||
|
||||
// Cut out the border ring channel
|
||||
translate([0, 0, -0.05])
|
||||
difference() {
|
||||
oval(total_width, total_height, blue_thickness + 0.1);
|
||||
oval(oval_width, oval_height, blue_thickness + 0.2);
|
||||
}
|
||||
|
||||
// Cut out text channels
|
||||
translate([0, 0, -0.05])
|
||||
bold_text();
|
||||
|
||||
// Cut out hole
|
||||
translate([hole_x, 0, -0.05])
|
||||
cylinder(h=blue_thickness + 0.1, d=hole_diameter, $fn=50);
|
||||
}
|
||||
BIN
Printing/Nameplates/test_debug.3mf
Normal file
BIN
Printing/Nameplates/test_debug.3mf
Normal file
Binary file not shown.
43
Printing/Nameplates/test_debug.scad
Normal file
43
Printing/Nameplates/test_debug.scad
Normal file
@@ -0,0 +1,43 @@
|
||||
// Debug - just show the blue layer with text cut out
|
||||
name = "Bennett";
|
||||
oval_width = 96;
|
||||
oval_height = 30;
|
||||
blue_thickness = 1;
|
||||
border_width = 2;
|
||||
|
||||
name_length = len(name);
|
||||
text_size = name_length <= 3 ? 18 :
|
||||
name_length <= 5 ? 13 :
|
||||
name_length <= 8 ? 11 :
|
||||
11;
|
||||
|
||||
total_width = oval_width + border_width*2;
|
||||
total_height = oval_height + border_width*2;
|
||||
|
||||
module oval(width, height, depth) {
|
||||
scale([width/2, height/2, 1])
|
||||
cylinder(h=depth, r=1, $fn=100);
|
||||
}
|
||||
|
||||
module bold_text() {
|
||||
for (x = [-0.3, 0, 0.3]) {
|
||||
for (y = [-0.3, 0, 0.3]) {
|
||||
translate([x, y, 0])
|
||||
linear_extrude(height=blue_thickness + 0.1)
|
||||
text(name,
|
||||
size=text_size,
|
||||
font="Fordscript",
|
||||
halign="center",
|
||||
valign="center");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Just the blue with text cut - no border cut
|
||||
color("RoyalBlue")
|
||||
difference() {
|
||||
oval(total_width, total_height, blue_thickness);
|
||||
|
||||
translate([0, 0, -0.05])
|
||||
bold_text();
|
||||
}
|
||||
3
Printing/Nameplates/test_font.scad
Normal file
3
Printing/Nameplates/test_font.scad
Normal file
@@ -0,0 +1,3 @@
|
||||
// Test if Fordscript font renders
|
||||
linear_extrude(height=2)
|
||||
text("Bennett", size=11, font="Fordscript", halign="center", valign="center");
|
||||
12
Printing/Nameplates/test_simple_fred.scad
Normal file
12
Printing/Nameplates/test_simple_fred.scad
Normal file
@@ -0,0 +1,12 @@
|
||||
// Simple test for Fred text rendering
|
||||
name = "Fred";
|
||||
text_size = 13;
|
||||
|
||||
color("white")
|
||||
translate([0, 0, 1.5])
|
||||
linear_extrude(height=1)
|
||||
text(name,
|
||||
size=text_size,
|
||||
font="Fordscript",
|
||||
halign="center",
|
||||
valign="center");
|
||||
70
Printing/Nameplates/zipper-pulls-raised-text-2/index.html
Normal file
70
Printing/Nameplates/zipper-pulls-raised-text-2/index.html
Normal file
@@ -0,0 +1,70 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Directory listing for /Printing/Nameplates/zipper-pulls-raised-text-2/</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Directory listing for /Printing/Nameplates/zipper-pulls-raised-text-2/</h1>
|
||||
<hr>
|
||||
<ul>
|
||||
<li><a href="Aaron.stl">Aaron.stl</a></li>
|
||||
<li><a href="Adalynn.stl">Adalynn.stl</a></li>
|
||||
<li><a href="Aiden.stl">Aiden.stl</a></li>
|
||||
<li><a href="Alexis.stl">Alexis.stl</a></li>
|
||||
<li><a href="Alice.stl">Alice.stl</a></li>
|
||||
<li><a href="Amaya.stl">Amaya.stl</a></li>
|
||||
<li><a href="Aniah.stl">Aniah.stl</a></li>
|
||||
<li><a href="Annabella.stl">Annabella.stl</a></li>
|
||||
<li><a href="Aur%27heir.stl">Aur'heir.stl</a></li>
|
||||
<li><a href="Ayden.stl">Ayden.stl</a></li>
|
||||
<li><a href="Ayla.stl">Ayla.stl</a></li>
|
||||
<li><a href="Bennett.stl">Bennett.stl</a></li>
|
||||
<li><a href="Bentley.stl">Bentley.stl</a></li>
|
||||
<li><a href="Blake.stl">Blake.stl</a></li>
|
||||
<li><a href="Bryant.stl">Bryant.stl</a></li>
|
||||
<li><a href="Carson.stl">Carson.stl</a></li>
|
||||
<li><a href="Charlotte.stl">Charlotte.stl</a></li>
|
||||
<li><a href="Clare.stl">Clare.stl</a></li>
|
||||
<li><a href="Clay.stl">Clay.stl</a></li>
|
||||
<li><a href="Cole.stl">Cole.stl</a></li>
|
||||
<li><a href="Danny.stl">Danny.stl</a></li>
|
||||
<li><a href="Donald.stl">Donald.stl</a></li>
|
||||
<li><a href="Eli.stl">Eli.stl</a></li>
|
||||
<li><a href="Grayson.stl">Grayson.stl</a></li>
|
||||
<li><a href="Harley.stl">Harley.stl</a></li>
|
||||
<li><a href="Harper.stl">Harper.stl</a></li>
|
||||
<li><a href="Hunter.stl">Hunter.stl</a></li>
|
||||
<li><a href="Jack.stl">Jack.stl</a></li>
|
||||
<li><a href="Jaxxin.stl">Jaxxin.stl</a></li>
|
||||
<li><a href="Jayden.stl">Jayden.stl</a></li>
|
||||
<li><a href="Jordan.stl">Jordan.stl</a></li>
|
||||
<li><a href="Karleigh.stl">Karleigh.stl</a></li>
|
||||
<li><a href="Karter.stl">Karter.stl</a></li>
|
||||
<li><a href="Kathrynn.stl">Kathrynn.stl</a></li>
|
||||
<li><a href="Keith.stl">Keith.stl</a></li>
|
||||
<li><a href="Kinleigh.stl">Kinleigh.stl</a></li>
|
||||
<li><a href="Landon.stl">Landon.stl</a></li>
|
||||
<li><a href="Lane.stl">Lane.stl</a></li>
|
||||
<li><a href="Leah.stl">Leah.stl</a></li>
|
||||
<li><a href="Leon.stl">Leon.stl</a></li>
|
||||
<li><a href="Liberty.stl">Liberty.stl</a></li>
|
||||
<li><a href="Lucy.stl">Lucy.stl</a></li>
|
||||
<li><a href="Max.stl">Max.stl</a></li>
|
||||
<li><a href="Michael.stl">Michael.stl</a></li>
|
||||
<li><a href="Nevaeh.stl">Nevaeh.stl</a></li>
|
||||
<li><a href="Nicholas.stl">Nicholas.stl</a></li>
|
||||
<li><a href="Oliver.stl">Oliver.stl</a></li>
|
||||
<li><a href="Shane.stl">Shane.stl</a></li>
|
||||
<li><a href="Silas.stl">Silas.stl</a></li>
|
||||
<li><a href="Skylar.stl">Skylar.stl</a></li>
|
||||
<li><a href="Sydney.stl">Sydney.stl</a></li>
|
||||
<li><a href="Taylor.stl">Taylor.stl</a></li>
|
||||
<li><a href="Tyler.stl">Tyler.stl</a></li>
|
||||
<li><a href="William.stl">William.stl</a></li>
|
||||
<li><a href="Wyatt.stl">Wyatt.stl</a></li>
|
||||
<li><a href="Zoey.stl">Zoey.stl</a></li>
|
||||
</ul>
|
||||
<hr>
|
||||
</body>
|
||||
</html>
|
||||
82
Printing/Nameplates/zipper-pulls-raised-text/index.html
Normal file
82
Printing/Nameplates/zipper-pulls-raised-text/index.html
Normal file
@@ -0,0 +1,82 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Directory listing for /Printing/Nameplates/zipper-pulls-raised-text/</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Directory listing for /Printing/Nameplates/zipper-pulls-raised-text/</h1>
|
||||
<hr>
|
||||
<ul>
|
||||
<li><a href="111.stl">111.stl</a></li>
|
||||
<li><a href="aaron.3mf">aaron.3mf</a></li>
|
||||
<li><a href="Aaron.stl">Aaron.stl</a></li>
|
||||
<li><a href="Adalynn.stl">Adalynn.stl</a></li>
|
||||
<li><a href="Aiden.stl">Aiden.stl</a></li>
|
||||
<li><a href="Alexis.stl">Alexis.stl</a></li>
|
||||
<li><a href="Alice.stl">Alice.stl</a></li>
|
||||
<li><a href="Amaya.stl">Amaya.stl</a></li>
|
||||
<li><a href="Aniah.stl">Aniah.stl</a></li>
|
||||
<li><a href="Annabella.stl">Annabella.stl</a></li>
|
||||
<li><a href="Aurheir.stl">Aurheir.stl</a></li>
|
||||
<li><a href="Ayden.stl">Ayden.stl</a></li>
|
||||
<li><a href="Ayla.stl">Ayla.stl</a></li>
|
||||
<li><a href="Bennett.stl">Bennett.stl</a></li>
|
||||
<li><a href="Bentley.stl">Bentley.stl</a></li>
|
||||
<li><a href="Blake.stl">Blake.stl</a></li>
|
||||
<li><a href="Bryant.stl">Bryant.stl</a></li>
|
||||
<li><a href="Carson.stl">Carson.stl</a></li>
|
||||
<li><a href="Charlotte.stl">Charlotte.stl</a></li>
|
||||
<li><a href="Clare.stl">Clare.stl</a></li>
|
||||
<li><a href="Clay.stl">Clay.stl</a></li>
|
||||
<li><a href="Cole.stl">Cole.stl</a></li>
|
||||
<li><a href="Daniel.stl">Daniel.stl</a></li>
|
||||
<li><a href="Danny.stl">Danny.stl</a></li>
|
||||
<li><a href="Donald.stl">Donald.stl</a></li>
|
||||
<li><a href="Eli.stl">Eli.stl</a></li>
|
||||
<li><a href="first%20plate.gcode">first plate.gcode</a></li>
|
||||
<li><a href="Ford-Fred%20%282%29.stl">Ford-Fred (2).stl</a></li>
|
||||
<li><a href="Grayson.stl">Grayson.stl</a></li>
|
||||
<li><a href="Harley.stl">Harley.stl</a></li>
|
||||
<li><a href="Harper.stl">Harper.stl</a></li>
|
||||
<li><a href="Hunter.stl">Hunter.stl</a></li>
|
||||
<li><a href="Jack.stl">Jack.stl</a></li>
|
||||
<li><a href="Jaxxin.stl">Jaxxin.stl</a></li>
|
||||
<li><a href="Jayden.stl">Jayden.stl</a></li>
|
||||
<li><a href="Jordan.stl">Jordan.stl</a></li>
|
||||
<li><a href="Karleigh.stl">Karleigh.stl</a></li>
|
||||
<li><a href="Karter.stl">Karter.stl</a></li>
|
||||
<li><a href="Kathrynn.stl">Kathrynn.stl</a></li>
|
||||
<li><a href="Keith.stl">Keith.stl</a></li>
|
||||
<li><a href="Kinleigh.stl">Kinleigh.stl</a></li>
|
||||
<li><a href="Landon.stl">Landon.stl</a></li>
|
||||
<li><a href="Lane.stl">Lane.stl</a></li>
|
||||
<li><a href="Leah.stl">Leah.stl</a></li>
|
||||
<li><a href="Leon.stl">Leon.stl</a></li>
|
||||
<li><a href="Liberty.stl">Liberty.stl</a></li>
|
||||
<li><a href="Lucy.stl">Lucy.stl</a></li>
|
||||
<li><a href="Max.stl">Max.stl</a></li>
|
||||
<li><a href="Michael.stl">Michael.stl</a></li>
|
||||
<li><a href="Nevaeh.stl">Nevaeh.stl</a></li>
|
||||
<li><a href="New%20Names.3mf">New Names.3mf</a></li>
|
||||
<li><a href="Nicholas.stl">Nicholas.stl</a></li>
|
||||
<li><a href="Oliver.stl">Oliver.stl</a></li>
|
||||
<li><a href="pLATE%201.3mf">pLATE 1.3mf</a></li>
|
||||
<li><a href="Shane.stl">Shane.stl</a></li>
|
||||
<li><a href="Silas.stl">Silas.stl</a></li>
|
||||
<li><a href="Skylar.stl">Skylar.stl</a></li>
|
||||
<li><a href="Sydney.stl">Sydney.stl</a></li>
|
||||
<li><a href="Taylor.stl">Taylor.stl</a></li>
|
||||
<li><a href="top4.3mf">top4.3mf</a></li>
|
||||
<li><a href="Tyler.stl">Tyler.stl</a></li>
|
||||
<li><a href="William.stl">William.stl</a></li>
|
||||
<li><a href="Wyatt.stl">Wyatt.stl</a></li>
|
||||
<li><a href="zipper%20pulls.3mf">zipper pulls.3mf</a></li>
|
||||
<li><a href="zipper%20pulls_FINAL.3mf">zipper pulls_FINAL.3mf</a></li>
|
||||
<li><a href="zipper%20pulls_modified.3mf">zipper pulls_modified.3mf</a></li>
|
||||
<li><a href="zipper%20pulls_with_M600.3mf">zipper pulls_with_M600.3mf</a></li>
|
||||
<li><a href="Zoey.stl">Zoey.stl</a></li>
|
||||
</ul>
|
||||
<hr>
|
||||
</body>
|
||||
</html>
|
||||
117
Printing/Nameplates/zipper_pull_raised_text_template.scad
Normal file
117
Printing/Nameplates/zipper_pull_raised_text_template.scad
Normal file
@@ -0,0 +1,117 @@
|
||||
// Face-Down Oval Zipper Pull Template
|
||||
// Designed for face-down printing: text and border are channels in blue layer (printed first),
|
||||
// then white backing fills the channels and covers the back.
|
||||
// When flipped over, shows white text/border on blue background.
|
||||
|
||||
// Parameters - these can be overridden from command line
|
||||
name = "NAME"; // Text to display on zipper pull
|
||||
oval_width = 96; // Width of blue oval (mm) - total with border will be 100mm (96 + 2*2)
|
||||
oval_height = 30; // Height of blue oval (mm) - total with border will be 34mm (30 + 2*2)
|
||||
blue_thickness = 1; // Thickness of blue layer (mm) - this is the "show" side
|
||||
white_thickness = 1.5; // Thickness of white backing layer (mm)
|
||||
base_text_size = 13; // Base font size for medium names
|
||||
|
||||
// Dynamic font sizing based on name length (mimics Ford oval proportions)
|
||||
// "Fred" (4 chars) at 13mm gives ~20% coverage - our target
|
||||
name_length = len(name);
|
||||
text_size = name_length <= 3 ? 18 : // Short names (Zoe, Sam, Al) - larger (~21% coverage)
|
||||
name_length <= 5 ? 13 : // Medium names (Fred, John, Mary) - standard (~20% coverage)
|
||||
name_length <= 8 ? 11 : // Longer names (Michael, Jessica) - smaller (~25% coverage)
|
||||
11; // Very long names (Christopher) - increased to 11mm (~35% coverage)
|
||||
|
||||
// Border parameters
|
||||
border_width = 2; // Width of the white border around the oval (mm)
|
||||
|
||||
// Hole parameters for zipper pull
|
||||
hole_diameter = 4; // Diameter of the hole (mm)
|
||||
hole_clearance = 4; // Minimum clearance from edge of outer border (mm)
|
||||
|
||||
// Total dimensions
|
||||
total_width = oval_width + border_width*2; // 100mm
|
||||
total_height = oval_height + border_width*2; // 34mm
|
||||
|
||||
// Hole position - on LEFT side when viewed from show side
|
||||
// Since we print face-down, hole appears on RIGHT during printing
|
||||
// When flipped, it will be on the left as expected
|
||||
hole_x = -(total_width/2) + (hole_diameter/2) + hole_clearance;
|
||||
|
||||
// Module to create an oval (ellipse)
|
||||
module oval(width, height, depth) {
|
||||
scale([width/2, height/2, 1])
|
||||
cylinder(h=depth, r=1, $fn=100);
|
||||
}
|
||||
|
||||
// Module for text with fake bold effect
|
||||
module bold_text() {
|
||||
for (x = [-0.3, 0, 0.3]) {
|
||||
for (y = [-0.3, 0, 0.3]) {
|
||||
translate([x, y, 0])
|
||||
linear_extrude(height=blue_thickness + 0.1)
|
||||
text(name,
|
||||
size=text_size,
|
||||
font="Fordscript",
|
||||
halign="center",
|
||||
valign="center");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Blue layer with channels for text and border (prints first, face-down)
|
||||
// The channels will be filled with white when the white layer is printed
|
||||
module blue_layer() {
|
||||
color("RoyalBlue")
|
||||
difference() {
|
||||
// Full blue oval
|
||||
oval(total_width, total_height, blue_thickness);
|
||||
|
||||
// Cut out the border ring channel (will be filled with white)
|
||||
translate([0, 0, -0.05])
|
||||
difference() {
|
||||
oval(total_width, total_height, blue_thickness + 0.1);
|
||||
oval(oval_width, oval_height, blue_thickness + 0.2);
|
||||
}
|
||||
|
||||
// Cut out text channels (will be filled with white)
|
||||
translate([0, 0, -0.05])
|
||||
bold_text();
|
||||
|
||||
// Cut out hole
|
||||
translate([hole_x, 0, -0.05])
|
||||
cylinder(h=blue_thickness + 0.1, d=hole_diameter, $fn=50);
|
||||
}
|
||||
}
|
||||
|
||||
// White backing layer (prints second, on top of blue)
|
||||
// Also fills the text and border channels
|
||||
module white_layer() {
|
||||
color("white")
|
||||
difference() {
|
||||
union() {
|
||||
// Main backing layer on top of blue
|
||||
translate([0, 0, blue_thickness])
|
||||
oval(total_width, total_height, white_thickness);
|
||||
|
||||
// Fill the border channel
|
||||
difference() {
|
||||
oval(total_width, total_height, blue_thickness);
|
||||
oval(oval_width, oval_height, blue_thickness + 0.1);
|
||||
}
|
||||
|
||||
// Fill the text channels
|
||||
bold_text();
|
||||
}
|
||||
|
||||
// Cut out hole through entire white layer
|
||||
translate([hole_x, 0, -0.05])
|
||||
cylinder(h=blue_thickness + white_thickness + 0.2, d=hole_diameter, $fn=50);
|
||||
}
|
||||
}
|
||||
|
||||
// Main zipper pull assembly
|
||||
module zipper_pull() {
|
||||
blue_layer();
|
||||
white_layer();
|
||||
}
|
||||
|
||||
// Generate the zipper pull
|
||||
zipper_pull();
|
||||
@@ -0,0 +1,88 @@
|
||||
// Single-Layer Oval Zipper Pull Template with Raised Text
|
||||
// Creates a blue base oval with raised white text and a hole for zipper attachment
|
||||
|
||||
// Parameters - these can be overridden from command line
|
||||
name = "NAME"; // Text to display on zipper pull
|
||||
oval_width = 96; // Width of blue oval (mm) - total with border will be 100mm (96 + 2*2)
|
||||
oval_height = 30; // Height of blue oval (mm) - total with border will be 34mm (30 + 2*2)
|
||||
base_thickness = 1.5; // Thickness of blue base layer (mm)
|
||||
text_thickness = 1; // Thickness of raised white text (mm)
|
||||
base_text_size = 13; // Base font size for medium names
|
||||
font_file = "C:/Users/Fred/claude/Fordscript.ttf"; // Path to the custom font file
|
||||
|
||||
// Dynamic font sizing based on name length (mimics Ford oval proportions)
|
||||
// "Fred" (4 chars) at 13mm gives ~20% coverage - our target
|
||||
name_length = len(name);
|
||||
text_size = name_length <= 3 ? 18 : // Short names (Zoe, Sam, Al) - larger
|
||||
name_length <= 5 ? 13 : // Medium names (Fred, John, Mary) - standard
|
||||
name_length <= 8 ? 11 : // Longer names (Michael, Jessica) - smaller
|
||||
9; // Very long names (Christopher) - smallest
|
||||
|
||||
// Border parameters
|
||||
border_width = 2; // Width of the white border around the oval (mm)
|
||||
border_thickness = 1; // Thickness of the white border (mm)
|
||||
|
||||
// Hole parameters for zipper pull
|
||||
hole_diameter = 4; // Diameter of the hole (mm)
|
||||
hole_clearance = 3; // Minimum clearance from edge of outer border (mm) - increased to fully clear white border
|
||||
|
||||
// Module to create an oval (ellipse)
|
||||
module oval(width, height, depth) {
|
||||
scale([width/2, height/2, 1])
|
||||
cylinder(h=depth, r=1, $fn=100);
|
||||
}
|
||||
|
||||
// Blue base layer with hole
|
||||
module base_layer() {
|
||||
color("RoyalBlue")
|
||||
difference() {
|
||||
// Blue base matches the outer size of the white border
|
||||
oval(oval_width + border_width*2, oval_height + border_width*2, base_thickness);
|
||||
|
||||
// Hole for zipper pull - positioned relative to outer edge
|
||||
// Total width = oval_width + border_width*2
|
||||
// Position: left edge + hole_radius + clearance
|
||||
total_width = oval_width + border_width*2;
|
||||
hole_x = -(total_width/2) + (hole_diameter/2) + hole_clearance;
|
||||
translate([hole_x, 0, -0.05])
|
||||
cylinder(h=base_thickness + 0.1, d=hole_diameter, $fn=50);
|
||||
}
|
||||
}
|
||||
|
||||
// White border around the oval
|
||||
module white_border() {
|
||||
color("white")
|
||||
translate([0, 0, base_thickness])
|
||||
difference() {
|
||||
// Outer oval (larger)
|
||||
oval(oval_width + border_width*2, oval_height + border_width*2, border_thickness);
|
||||
// Inner oval (cut out the center)
|
||||
translate([0, 0, -0.05])
|
||||
oval(oval_width, oval_height, border_thickness + 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
// Raised white text on top of base - REDUCED bold effect (3 renders instead of 9)
|
||||
module raised_text() {
|
||||
color("white")
|
||||
// Reduced bold effect - only 3 offsets
|
||||
for (x = [-0.4, 0, 0.4]) {
|
||||
translate([x, 0, base_thickness])
|
||||
linear_extrude(height=text_thickness)
|
||||
text(name,
|
||||
size=text_size,
|
||||
font="Fordscript",
|
||||
halign="center",
|
||||
valign="center");
|
||||
}
|
||||
}
|
||||
|
||||
// Main zipper pull assembly
|
||||
module zipper_pull() {
|
||||
base_layer();
|
||||
white_border();
|
||||
raised_text();
|
||||
}
|
||||
|
||||
// Generate the zipper pull
|
||||
zipper_pull();
|
||||
90
Printing/Nameplates/zipper_pull_template.scad
Normal file
90
Printing/Nameplates/zipper_pull_template.scad
Normal file
@@ -0,0 +1,90 @@
|
||||
// Two-Layer Oval Zipper Pull Template with Engraved Text
|
||||
// Creates a white base oval with a blue top oval, engraved text, and a hole for zipper attachment
|
||||
|
||||
// Parameters - these can be overridden from command line
|
||||
name = "NAME"; // Text to display on zipper pull
|
||||
oval_width = 96; // Width of blue oval (mm) - white base will be 100mm total (96 + 2*2)
|
||||
oval_height = 30; // Height of blue oval (mm) - white base will be 34mm total (30 + 2*2)
|
||||
base_thickness = 1.5; // Thickness of white base layer (mm)
|
||||
top_thickness = 1; // Thickness of blue top layer (mm)
|
||||
base_offset = 2; // How much larger the white base is (mm)
|
||||
base_text_size = 13; // Base font size for medium names (reduced to prevent interference with hole)
|
||||
text_depth = 1; // How deep the text is engraved (mm) - cuts through blue to show white
|
||||
font_file = "C:/Users/Fred/claude/Fordscript.ttf"; // Path to the custom font file
|
||||
|
||||
// Dynamic font sizing based on name length (mimics Ford oval proportions)
|
||||
// "Fred" (4 chars) at 13mm gives ~20% coverage - our target
|
||||
name_length = len(name);
|
||||
text_size = name_length <= 3 ? 18 : // Short names (Zoe, Sam, Al) - larger
|
||||
name_length <= 5 ? 13 : // Medium names (Fred, John, Mary) - standard
|
||||
name_length <= 8 ? 11 : // Longer names (Michael, Jessica) - smaller
|
||||
9; // Very long names (Christopher) - smallest
|
||||
|
||||
// Hole parameters for zipper pull
|
||||
hole_diameter = 4; // Diameter of the hole (mm)
|
||||
hole_clearance = 1; // Minimum clearance from edge of white base layer (mm)
|
||||
|
||||
// Module to create an oval (ellipse)
|
||||
module oval(width, height, depth) {
|
||||
scale([width/2, height/2, 1])
|
||||
cylinder(h=depth, r=1, $fn=100);
|
||||
}
|
||||
|
||||
// White base layer (larger oval) with hole
|
||||
module base_layer() {
|
||||
color("white")
|
||||
difference() {
|
||||
oval(
|
||||
oval_width + base_offset*2,
|
||||
oval_height + base_offset*2,
|
||||
base_thickness
|
||||
);
|
||||
|
||||
// Hole for zipper pull - positioned relative to white base edge
|
||||
// Calculate from white base width: (oval_width + base_offset*2)
|
||||
white_width = oval_width + base_offset*2;
|
||||
hole_x = -(white_width/2) + (hole_diameter/2) + hole_clearance;
|
||||
translate([hole_x, 0, -0.05])
|
||||
cylinder(h=base_thickness + 0.1, d=hole_diameter, $fn=50);
|
||||
}
|
||||
}
|
||||
|
||||
// Blue top layer with engraved text and hole
|
||||
module top_layer() {
|
||||
color("RoyalBlue")
|
||||
difference() {
|
||||
// Blue oval
|
||||
translate([0, 0, base_thickness])
|
||||
oval(oval_width, oval_height, top_thickness);
|
||||
|
||||
// Engraved text (cuts into the blue layer)
|
||||
// Multiple offset renders create a "fake bold" effect
|
||||
for (x = [-0.3, 0, 0.3]) {
|
||||
for (y = [-0.3, 0, 0.3]) {
|
||||
translate([x, y, base_thickness + top_thickness - text_depth + 0.01])
|
||||
linear_extrude(height=text_depth)
|
||||
text(name,
|
||||
size=text_size,
|
||||
font="Fordscript",
|
||||
halign="center",
|
||||
valign="center");
|
||||
}
|
||||
}
|
||||
|
||||
// Hole for zipper pull (positioned on left side)
|
||||
// Position: matches white base layer hole position
|
||||
white_width = oval_width + base_offset*2;
|
||||
hole_x = -(white_width/2) + (hole_diameter/2) + hole_clearance;
|
||||
translate([hole_x, 0, base_thickness])
|
||||
cylinder(h=top_thickness + 0.1, d=hole_diameter, $fn=50);
|
||||
}
|
||||
}
|
||||
|
||||
// Main zipper pull assembly
|
||||
module zipper_pull() {
|
||||
base_layer();
|
||||
top_layer();
|
||||
}
|
||||
|
||||
// Generate the zipper pull
|
||||
zipper_pull();
|
||||
20
Printing/index.html
Normal file
20
Printing/index.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Directory listing for /Printing/</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Directory listing for /Printing/</h1>
|
||||
<hr>
|
||||
<ul>
|
||||
<li><a href=".claude/">.claude/</a></li>
|
||||
<li><a href=".git">.git</a></li>
|
||||
<li><a href=".gitignore">.gitignore</a></li>
|
||||
<li><a href="CLAUDE.md">CLAUDE.md</a></li>
|
||||
<li><a href="Key%20caps/">Key caps/</a></li>
|
||||
<li><a href="Nameplates/">Nameplates/</a></li>
|
||||
</ul>
|
||||
<hr>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user