diff --git a/kjvstudy_org/server.py b/kjvstudy_org/server.py index e7eb399..deeba75 100644 --- a/kjvstudy_org/server.py +++ b/kjvstudy_org/server.py @@ -4226,6 +4226,136 @@ def family_tree_search_page(request: Request, q: str = ""): ) +@app.get("/family-tree/lineage", response_class=HTMLResponse) +def family_tree_lineage_page(request: Request): + """Dedicated page for the Messianic lineage visualization""" + books = list(bible.iter_books()) + + return templates.TemplateResponse( + "family_tree_lineage.html", + { + "request": request, + "books": books, + "breadcrumbs": [ + {"text": "Home", "url": "/"}, + {"text": "Family Tree", "url": "/family-tree"}, + {"text": "Messianic Lineage", "url": None} + ] + } + ) + + +@app.get("/family-tree/lineage.svg") +def family_tree_lineage_svg(request: Request): + """Generate SVG visualization of the Messianic lineage (Adam to Jesus)""" + static_dir = Path(__file__).parent / "static" + gedcom_path = static_dir / "adameve.ged" + + if not gedcom_path.exists() or not GedcomReader: + raise HTTPException(status_code=404, detail="Family tree data not available") + + try: + family_tree_data, generations = parse_gedcom_to_tree_data(gedcom_path) + except Exception as e: + raise HTTPException(status_code=500, detail=f"Failed to parse family tree: {str(e)}") + + # Find Jesus and trace back through Kekulé #1 ancestors (powers of 2 in father line) + # Kekulé numbering: 1 = subject, 2 = father, 4 = paternal grandfather, 8 = paternal great-grandfather, etc. + lineage = [] + + # Find all people with Kekulé numbers that are powers of 2 (direct paternal line) + # This includes: 1, 2, 4, 8, 16, 32, 64, 128, etc. + for person_id, person in family_tree_data.items(): + kekule = person.get("kekule_number") + if kekule and kekule > 0: + # Check if kekule is a power of 2 + if kekule & (kekule - 1) == 0: + lineage.append({ + "id": person_id, + "name": person["name"], + "kekule": kekule, + "generation": person.get("generation", 0), + "birth_year": person.get("birth_year", "Unknown"), + "death_year": person.get("death_year", "Unknown") + }) + + # Sort by Kekulé number (descending = Adam to Jesus) + lineage.sort(key=lambda x: -x["kekule"]) + + # Generate SVG + width = 800 + node_height = 80 + node_width = 700 + margin_top = 40 + margin_bottom = 40 + vertical_spacing = 20 + + height = margin_top + (len(lineage) * (node_height + vertical_spacing)) + margin_bottom + + svg_parts = [ + f'', + f'', + '', + '', + '', + ] + + x = (width - node_width) / 2 + + # Draw connector lines first (so they appear behind boxes) + for i in range(len(lineage) - 1): + y1 = margin_top + (i * (node_height + vertical_spacing)) + node_height + y2 = margin_top + ((i + 1) * (node_height + vertical_spacing)) + mid_x = x + (node_width / 2) + svg_parts.append(f'') + + # Draw person boxes + for i, person in enumerate(lineage): + y = margin_top + (i * (node_height + vertical_spacing)) + + # Draw box with link + svg_parts.append(f'') + svg_parts.append(f'') + + # Name + name_y = y + 28 + svg_parts.append(f'{person["name"]}') + + # Dates + dates_text = "" + if person["birth_year"] != "Unknown" and person["death_year"] != "Unknown": + dates_text = f'{person["birth_year"]} – {person["death_year"]}' + elif person["birth_year"] != "Unknown": + dates_text = f'Born {person["birth_year"]}' + elif person["death_year"] != "Unknown": + dates_text = f'Died {person["death_year"]}' + + if dates_text: + dates_y = y + 48 + svg_parts.append(f'{dates_text}') + + # Meta (generation and Kekulé number) + meta_text = f'Generation {person["generation"]}' + if person["kekule"] > 1: + meta_text += f' • Kekulé #{person["kekule"]}' + meta_y = y + 66 + svg_parts.append(f'{meta_text}') + + svg_parts.append('') + + svg_parts.append('') + + svg_content = '\n'.join(svg_parts) + return Response(content=svg_content, media_type="image/svg+xml") + + def expand_book_abbreviation(abbrev): """Expand common Bible book abbreviations to full names""" abbreviations = { diff --git a/kjvstudy_org/templates/family_tree.html b/kjvstudy_org/templates/family_tree.html index c6efeda..0dfb578 100644 --- a/kjvstudy_org/templates/family_tree.html +++ b/kjvstudy_org/templates/family_tree.html @@ -135,6 +135,13 @@ section:nth-of-type(3) { +
+

Quick Links

+

+ View the Messianic Lineage — A visual genealogy showing the direct paternal line from Adam to Jesus Christ. +

+
+

The Generations

diff --git a/kjvstudy_org/templates/family_tree_lineage.html b/kjvstudy_org/templates/family_tree_lineage.html new file mode 100644 index 0000000..7ae7828 --- /dev/null +++ b/kjvstudy_org/templates/family_tree_lineage.html @@ -0,0 +1,36 @@ +{% extends "base.html" %} + +{% block title %}The Messianic Lineage - Biblical Family Tree - KJV Study{% endblock %} +{% block description %}The direct paternal line from Adam to Jesus Christ, traced through biblical genealogies.{% endblock %} + +{% block content %} +

The Messianic Lineage

+

The Direct Paternal Line from Adam to Jesus Christ

+ +
+

This visualization traces the direct paternal line from Adam, the first man, through the patriarchs, kings, and prophets, culminating in Jesus Christ. The genealogy is calculated using the Kekulé numbering system (also known as Ahnentafel), where each person's father has a number that is double their own.

+ +

This represents the genealogical record preserved in Scripture (Genesis 5, Genesis 11, Ruth 4:18-22, 1 Chronicles 1-3, Matthew 1, Luke 3), showing God's redemptive plan working through specific family lines across the generations.

+ +

← Back to Family Tree

+
+ +
+
+ Messianic Lineage from Adam to Jesus Christ +
+
+ +
+

About the Kekulé Numbering System

+

The Kekulé number (Ahnentafel number) is a genealogical numbering system where:

+ +

The direct paternal line consists of all ancestors with Kekulé numbers that are powers of 2: 1, 2, 4, 8, 16, 32, 64, etc. This visualization shows only these direct ancestors, creating a clear line from Adam to Christ.

+
+{% endblock %}