# Contributing

There are two kinds of artwork you can contribute to GFL, and they use
different paths:

- **Hardware standards** (ISO/DIN fasteners) — generated from a config file by
  the `hardware-gen` pipeline. See *Contributing a standard* below.
- **Custom images** (any icon you want available in the label editor) — drawn
  or traced in the browser and submitted as a single SVG. See *Contributing a
  custom image* below.

---

## Contributing a custom image (recommended for most people)

Custom images live in [`images/custom/`](images/custom/) as plain SVG files and
show up in the app under **Icon → Custom**. The manifest the app reads
(`custom-icons.json`) is **generated** from that directory — you only ever edit
one SVG file.

### In-browser flow

1. Open the contribute page: <https://gcormier.github.io/gfl/contribute.html>
   (or **Icon → Custom → Create or contribute a custom image →** in the app).
2. **Generate from Image** (optional) — drop or paste an engineering drawing /
   logo / silhouette and drag to select a region. Tune **Threshold** and
   **Simplify**; the JSCad editor below fills in live as you adjust, so what you
   see in the preview is always what's in the code.
3. **Design (JSCad)** — refine the outline, or write 2D geometry from scratch.
   `main()` must return a single 2D shape. Click **▶ Run** to preview.
4. Click **Submit Custom Image…**, enter a **Name**, **Keywords** (comma
   separated — used for search), and a **filename id** (lowercase letters,
   digits, dashes, e.g. `hex-wrench`).
5. Click **Open on GitHub →**. A new tab opens with the SVG pre-filled. GitHub
   offers to fork the repo and walks you through opening a pull request.

No tokens, no OAuth, no local clone needed. Once merged, the icon appears under
**Icon → Custom** for everyone. While your PR is in review you can **Export
SVG ↓** and use it immediately via **Icon → Upload SVG…**.

### SVG metadata (required)

Each contributed SVG must be self-describing so the manifest can be rebuilt from
the directory alone. The contribute page writes this for you, but if you
hand-craft an SVG it must contain:

```xml
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <title>Hex Wrench</title>           <!-- name (required, non-empty) -->
  <desc>tool, allen, hardware</desc>   <!-- comma-separated keywords (required) -->
  <path d="…"/>                        <!-- at least one path (required) -->
</svg>
```

The app reads only the **first** `<path d="…">`. CI fails any SVG missing a
`<title>`, `<desc>` keywords, or a path, or with a non-conforming filename.
Note: SVG optimizers (e.g. SVGO) strip `<title>`/`<desc>` by default — don't run
one, or re-add the metadata afterward.

### Regenerating the manifest locally (optional)

```bash
cd hardware-gen
uv run python generate_custom_icons.py          # rebuild ../custom-icons.json
uv run python generate_custom_icons.py --check   # validate + verify in sync
```

---

## Contributing a standard

Hardware standards (the searchable ISO/DIN fastener catalog) are **not** drawn
by hand. They are generated by the `hardware-gen` pipeline from a single
source-of-truth YAML config, with accurate geometry produced by FreeCAD + the
Fasteners workbench.

`standards.json` (root) is a **generated, git-ignored artifact** — it is built at
deploy time and never committed, so never edit it directly.

To add or change a standard:

1. Look up valid sizes and lengths for the standard using the scaffold tool:

   ```bash
   cd hardware-gen
   hardware-gen scaffold ISO8752              # emit a ready-to-paste render snippet
   hardware-gen scaffold ISO8752 --list       # show all valid sizes and lengths
   ```

   You can also browse the full parameter reference without running any tools:
   [`hardware-gen/docs/fastener-parameters.md`](hardware-gen/docs/fastener-parameters.md)

2. Edit the relevant config file under
   [`hardware-gen/config/`](hardware-gen/config/) (`bolts_screws.yaml`,
   `nuts.yaml`, `washers.yaml`, or `misc.yaml`). Each file is the single
   source of truth for both the catalog metadata and the geometry render recipe.
   Paste the scaffold output into the `renders:` key of the appropriate entry.
3. Commit **only** the YAML and open a PR. Do **not** commit `standards.json` (it is
   git-ignored and built at deploy time) or the rendered SVGs.
4. On merge to `main`, CI (`hardware-gen.yml`) renders the geometry with FreeCAD and
   commits the `hardware-gen/output/*.svg`, then the Pages deploy regenerates
   `standards.json`. The standard goes live automatically.

If you have FreeCAD set up locally (see [`hardware-gen/README.md`](hardware-gen/README.md))
you can preview the geometry before opening the PR:

```bash
cd hardware-gen
uv run generate.py                        # 3D solids + 2D SVGs
uv run python generate_standards_json.py  # build a local (git-ignored) ../standards.json
```

CI (`hardware-gen.yml`) lints the pipeline, dry-runs the YAML, and runs the generators
as a **validation gate** on every relevant push/PR — there is no committed
`standards.json` / `custom-icons.json` to diff against; both are generated at deploy time.

### Naming

Prefer the **ISO** number when both ISO and DIN equivalents exist (ISO is
international). Standard ids use lowercase with no separators, e.g. `iso4762`.

---

## Local development

```bash
git clone https://github.com/gcormier/gfl.git
cd gfl
python -m http.server 8000   # then visit http://localhost:8000/
```

The frontend is plain static files — no build step. Any change to HTML/CSS/JS/
JSON requires bumping the version in the `VERSION` file and `APP_VERSION` in
`app.js`.
