---
name: Homepage Maker 3 → Publii Migrations-Memory
description: Spezifisches Wissen zur Migration von Homepage Maker 3 (Schultze-Williams Software) nach Publii – ergänzt das generische Publii-Memory
type: project
---

# Homepage Maker 3 → Publii: Migrations-Wissen

Quelle: https://www.logies.de/claude-code-memory-fuer-publii/
Erstellt: 2026-03-13

Dieses Memory ergänzt `publii-claude-memory.md` (generisches Publii-Memory).
Installiere beide Dateien im Memory-Verzeichnis deines Claude Code-Projekts.

## Was ist Homepage Maker 3?

Homepage Maker 3 (Schultze-Williams Software, ~1999–2005) war ein Windows-Programm
für private und kleine gewerbliche Websites. Charakteristika:
- **Table-basiertes Layout** (kein CSS-Grid, kein Flexbox)
- Kein responsives Design → Google-Ranking-Abstrafung seit ~2015
- Proprietäre Projekteigene Datei (.hmp) + generiertes HTML/CSS
- Navigation als Bildmap oder Tabelle
- Oft noch aktiv auf kleinen Unternehmensseiten (Ärzte, Handwerker, Vereine)

## Typisches HM3-HTML-Grundgerüst

```html
<html>
<head><title>Seitenname</title></head>
<body bgcolor="#FFFFFF">
<table width="780" border="0" cellpadding="0" cellspacing="0" align="center">
  <tr>
    <td colspan="2"><img src="images/header.jpg" width="780" height="80"></td>
  </tr>
  <tr>
    <!-- Linke Navigationsspalte -->
    <td width="150" valign="top">
      <a href="index.htm">Startseite</a><br>
      <a href="praxis.htm">Praxis</a><br>
      ...
    </td>
    <!-- Rechte Inhaltsspalte -->
    <td width="630" valign="top">
      <h2>Überschrift</h2>
      <p>Inhalt...</p>
      <img src="images/foto.jpg" width="200" height="150">
    </td>
  </tr>
  <tr>
    <td colspan="2">Fußzeile / Impressum</td>
  </tr>
</table>
</body>
</html>
```

## Konversionsstrategie

### Schritt 1: Inhalte von der Live-Site abrufen

```python
import requests
from bs4 import BeautifulSoup

def fetch_page(url):
    resp = requests.get(url, timeout=15)
    resp.encoding = resp.apparent_encoding  # HM3: oft Latin-1 oder Windows-1252
    return BeautifulSoup(resp.text, 'html.parser')

# Inhaltsspalte (rechte TD) extrahieren:
def extract_content(soup):
    tables = soup.find_all('table')
    if not tables:
        return soup.find('body')
    main_table = max(tables, key=lambda t: len(t.get_text()))
    tds = main_table.find_all('td', recursive=False) or           main_table.find('tr').find_all('td')
    # Rechte/größte TD = Inhalt:
    return max(tds, key=lambda td: len(td.get_text()))
```

### Schritt 2: HTML bereinigen

```python
import re

def clean_hm3_html(content_td, base_url, post_id):
    # Navigations-Elemente entfernen (linke Spalte wurde bereits ausgeschlossen)
    # Bild-Pfade auf Publii-Format umschreiben:
    for img in content_td.find_all('img'):
        src = img.get('src', '')
        filename = os.path.basename(src)
        img['src'] = f'#DOMAIN_NAME#{filename}'
        img['loading'] = 'lazy'
        img['class'] = 'post-img'

    # Interne Links auf Publii-Slugs umstellen:
    link_map = {
        'index.htm': '/',
        'praxis.htm': '/praxis/',
        'impressum.htm': '/impressum/',
        # ...weitere Seiten ergänzen
    }
    for a in content_td.find_all('a'):
        href = a.get('href', '')
        if href in link_map:
            a['href'] = link_map[href]
        elif href.startswith('http'):
            a['target'] = '_blank'
            a['rel'] = 'noopener noreferrer'

    # Table-Layout entfernen (Navigations-Tabellen):
    for table in content_td.find_all('table'):
        # Nur Daten-Tabellen behalten (z.B. Sprechzeiten):
        if len(table.find_all('td')) < 4:
            table.unwrap()

    return str(content_td)
```

### Schritt 3: Bilder herunterladen und skalieren

```python
from PIL import Image
import requests, io, os

def download_and_scale(img_url, dest_dir, post_id):
    resp = requests.get(img_url, timeout=15)
    img = Image.open(io.BytesIO(resp.content))

    filename = os.path.basename(img_url)
    base, ext = os.path.splitext(filename)

    # Thumbnail (max. 640×480):
    thumb = img.copy()
    if thumb.width > thumb.height:
        thumb.thumbnail((640, 480), Image.LANCZOS)
    else:
        thumb.thumbnail((480, 640), Image.LANCZOS)
    thumb_name = f"{base.lower()}.jpg"
    thumb.save(f"{dest_dir}/{thumb_name}", "JPEG", quality=85)

    # Original auf max. 1200px skalieren:
    orig = img.copy()
    orig.thumbnail((1200, 1200), Image.LANCZOS)
    orig.save(f"{dest_dir}/{base.lower()}-orig.jpg", "JPEG", quality=85)

    # Responsive-Varianten:
    breakpoints = [
        ("xs", 640), ("sm", 768), ("md", 1024),
        ("lg", 1366), ("xl", 1600), ("2xl", 1920)
    ]
    os.makedirs(f"{dest_dir}/responsive", exist_ok=True)
    for suffix, max_size in breakpoints:
        variant = img.copy()
        if variant.width > variant.height:
            if variant.width > max_size:
                variant.thumbnail((max_size, max_size * 10), Image.LANCZOS)
        else:
            if variant.height > max_size:
                variant.thumbnail((max_size * 10, max_size), Image.LANCZOS)
        variant.save(f"{dest_dir}/responsive/{base.lower()}-{suffix}.jpg",
                     "JPEG", quality=82)

    return thumb_name
```

## HM3-Bilddateinamen-Muster

Kamerafotos aus der HM3-Zeit folgen oft diesem Muster:
- **Kamera-Originale:** `SANY1234.JPG` (Großbuchstaben, SANYO-Kameras verbreitet)
- **HM3-Thumbnails:** `sany1234vorschau.jpg` (lowercase, `vorschau`-Suffix)
- **Mapping-Regel:** `{name}vorschau.jpg` → Original = `{NAME.upper()}.JPG`

```python
def find_original(thumb_name):
    base = thumb_name.replace("vorschau.jpg", "")
    candidates = [
        f"{base.upper()}.JPG",
        f"{base}.jpg",
        f"{base}-orig.jpg",
    ]
    return candidates
```

## Seitenstruktur-Mapping HM3 → Publii

| HM3-Element | Publii-Entsprechung |
|-------------|---------------------|
| `index.htm` | Seite `slug='startseite'`, `status='published,is-page'` |
| Unterseite `seite.htm` | Seite `slug='seite'`, `status='published,is-page'` |
| HM3-Navigation | `menu.config.json`, `type='page'`, `link=DB-ID` |
| Frames-basiertes Layout | Kein Frames-Äquivalent in Publii – Inhalt auf eine Seite |
| HM3-Gästebuch | Nicht migrieren (veraltet, Spam-Gefahr) |
| HM3-Besucherzähler | Nicht migrieren (Datenschutz, veraltet) |
| Externe Links | `type='external'` im Menü (NICHT `type='url'`!) oder `<a href="..." target="_blank">` im Text |

## Typische HM3-Seitenhierarchie (Beispiel Arztpraxis)

```
Startseite (index.htm)
├── Praxis (praxis.htm) – Öffnungszeiten, Anfahrt, Team
├── Leistungen (leistungen.htm) – Übersicht
│   ├── Leistung 1 (leistung1.htm)
│   └── ...
├── Für Kollegen (kollegen.htm) – Fachinfos, Überweisungen
├── Links (links.htm) – Externe Ressourcen für Patienten
└── Impressum (impressum.htm) – Pflichtangaben
```

## Zeichencodierung beachten

HM3 erzeugte oft HTML mit Windows-1252 oder Latin-1-Encoding:
```python
import chardet

def detect_encoding(raw_bytes):
    result = chardet.detect(raw_bytes)
    return result['encoding'] or 'utf-8'

resp = requests.get(url)
html = resp.content.decode(detect_encoding(resp.content), errors='replace')
```

## Qualitätsprüfung nach Migration

Checkliste nach abgeschlossener HM3→Publii-Migration:

- [ ] Alle HM3-Seiten als Publii-Seiten angelegt? (Seitenzahl vergleichen)
- [ ] Alle internen Links auf Publii-Slugs umgestellt (`/slug/` statt `seite.htm`)?
- [ ] Alle externen Links mit `target="_blank" rel="noopener noreferrer"`?
- [ ] Keine `bgcolor`-, `width`-, `align`-Attribute in HTML (veraltet)?
- [ ] Bilder responsiv (6 Breakpoint-Varianten je Bild vorhanden)?
- [ ] Original-Bilder auf max. 1200 px skaliert?
- [ ] `input/media/` und `preview/media/` identisch?
- [ ] Menü-Einträge alle mit numerischer DB-ID verlinkt?
- [ ] `metaTitle` und `metaDesc` fuer jede Seite in `posts_additional_data` (key `_core`) befuellt?
- [ ] `position`-Feld in `menu.config.json` vorhanden?
- [ ] Sprechzeiten als `<table>` mit `<thead>/<tbody>` ausgezeichnet?
- [ ] Impressum/Datenschutz DSGVO-konform aktualisiert?
- [ ] Kontaktdaten (Telefon, E-Mail, Adresse) korrekt?
- [ ] Publii Preview gestartet und alle Seiten manuell durchgeklickt?
- [ ] Mobile Ansicht in Browser-DevTools geprüft?
- [ ] Bilder auf Mobilgerät nicht matschig oder fehlernd?
