🌌 Constellation Guide: Die Sternenkarte des Wissens

Crumbforest Visualization Documentation
Version: 1.0
Datum: 2026-01-22
Live Demo: https://crumbforest.194-164-194-191.sslip.io/constellation/


"Wissen ist keine Liste.
Wissen ist eine Landschaft.
Kinder navigieren Sterne, nicht Zeilen."


🎯 Was ist die Constellation?

Nicht

❌ Eine Tabelle
❌ Eine Liste
❌ Ein Baum-Diagramm
❌ Ein Mind-Map

Sondern

✅ Eine 3D-Wissenslandschaft
✅ Ein semantischer Raum
✅ Eine lebendige Karte
✅ Ein Navigations-Tool

🌟 Die Grundkonzepte

1. Sterne = Embeddings

Jede Frage ist ein Stern
Jede Antwort ist ein Stern
Jeder Way ist ein Stern
Jedes Dokument ist ein Stern

→ Ein Stern = Ein Punkt im 768-dimensionalen Raum
→ Reduziert auf 3D für Visualisierung (x, y, z)

Beispiel:

Frage: "Was ist ein Nullfeld?"
→ Embedding: [0.23, -0.45, 0.67, ... 768 Werte]
→ 3D-Position: [0.2, 0.5, 0.8]
→ Stern an Koordinate (0.2, 0.5, 0.8)

2. Nähe = Ähnlichkeit

Nahe Sterne = Ähnliche Konzepte
Ferne Sterne = Unähnliche Konzepte

Distanz = Cosine Distance
Similarity = 1 - Distance

Beispiel:
- "Nullfeld" ↔ "Note 0": 0.92 (sehr nah)
- "Nullfeld" ↔ "FPGA": 0.45 (mittel)
- "Nullfeld" ↔ "Raspberry": 0.23 (fern)

Visuell:

      ⭐ Note 0
     /
    /  (nah)
   /
  ⭐ Nullfeld
           \
            \  (mittel)
             \
              ⭐ FPGA
                     \
                      \  (fern)
                       \
                        ⭐ Raspberry

3. Cluster = Themengebiete

Cluster entstehen organisch:
- Viele nahe Sterne = Ein Cluster
- Cluster haben ein "Zentrum" (Centroid)
- Cluster haben eine "Größe" (Radius)

Algorithmus: DBSCAN oder K-Means

Beispiel Cluster:
🌌 "Philosophie":
   ⭐ Nullfeld (Zentrum)
   ⭐ Note 0
   ⭐ Autonomie
   ⭐ Balance

🌌 "Hardware":
   ⭐ FPGA (Zentrum)
   ⭐ Raspberry Pi
   ⭐ LoRa
   ⭐ ESP32

4. Verbindungen = Resonanz

Verbindung zwischen Sternen wenn:
- Similarity > Schwelle (z.B. 0.7)
- Oder: Explizite Referenz (Link)
- Oder: Gleicher Author/Tag

Stärke der Verbindung:
- Dünn: 0.7-0.8 (schwach)
- Mittel: 0.8-0.9 (gut)
- Dick: 0.9-1.0 (sehr stark)

Visuell:

⭐ Nullfeld ━━━━━━━━━ ⭐ Note 0  (stark)
           ╲
            ╲─────── ⭐ Way #01  (mittel)
             ╲
              ⋯⋯⋯⋯⋯ ⭐ FPGA    (schwach)

🎨 Wie wird visualisiert?

Dimensionsreduktion (768D → 3D)

from sklearn.decomposition import PCA

# 768-dimensionale Embeddings
embeddings = [
    [0.23, -0.45, 0.67, ..., 0.12],  # 768 Werte
    [0.11, -0.23, 0.45, ..., 0.34],
    # ... 5.000 Embeddings
]

# Reduziere auf 3D
pca = PCA(n_components=3)
positions_3d = pca.fit_transform(embeddings)

# Resultat:
# [
#   [0.2, 0.5, 0.8],   # x, y, z für Stern 1
#   [0.3, 0.4, 0.6],   # x, y, z für Stern 2
#   ...
# ]

Wichtig:
- PCA behält relative Distanzen bei
- Nahe im 768D → Nahe im 3D
- Nicht perfekt, aber gut genug!


Clustering (DBSCAN)

from sklearn.cluster import DBSCAN

# Cluster finden
clustering = DBSCAN(
    eps=0.3,           # Max Distance zwischen Punkten
    min_samples=5      # Min Punkte für Cluster
).fit(positions_3d)

# Labels: [0, 0, 1, 1, 1, -1, 2, 2, ...]
# 0, 1, 2 = Cluster IDs
# -1 = Noise (kein Cluster)

# Cluster-Info extrahieren
clusters = {}
for i, label in enumerate(clustering.labels_):
    if label == -1:
        continue  # Skip noise

    if label not in clusters:
        clusters[label] = []

    clusters[label].append(i)

# Resultat:
# {
#   0: [0, 1, 5, 23, ...],     # Cluster "Philosophie"
#   1: [2, 3, 4, 12, ...],     # Cluster "Hardware"
#   2: [6, 7, 8, 15, ...],     # Cluster "Ways"
# }

Rendering (Three.js)

// constellation.js

import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';

// Scene Setup
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x000020);  // Dark blue

const camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
);
camera.position.z = 5;

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// Controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;

// Add Stars
function addStars(positions, metadata) {
    const geometry = new THREE.BufferGeometry();
    geometry.setAttribute(
        'position',
        new THREE.Float32BufferAttribute(positions.flat(), 3)
    );

    // Colors based on cluster
    const colors = [];
    metadata.forEach(meta => {
        const clusterColor = getClusterColor(meta.cluster);
        colors.push(...clusterColor);
    });
    geometry.setAttribute(
        'color',
        new THREE.Float32BufferAttribute(colors, 3)
    );

    const material = new THREE.PointsMaterial({
        size: 0.05,
        vertexColors: true,
        transparent: true,
        opacity: 0.8
    });

    const stars = new THREE.Points(geometry, material);
    scene.add(stars);

    return stars;
}

// Add Connections
function addConnections(connections) {
    const material = new THREE.LineBasicMaterial({
        color: 0x4488ff,
        transparent: true,
        opacity: 0.3
    });

    connections.forEach(conn => {
        const geometry = new THREE.BufferGeometry().setFromPoints([
            new THREE.Vector3(...conn.from),
            new THREE.Vector3(...conn.to)
        ]);

        const line = new THREE.Line(geometry, material);
        scene.add(line);
    });
}

// Animation Loop
function animate() {
    requestAnimationFrame(animate);
    controls.update();
    renderer.render(scene, camera);
}
animate();

📖 Wie lesen?

Für Kinder

"Stell dir vor, jede Frage die du stellst wird ein Stern im Himmel.

Wenn du eine ähnliche Frage stellst, wird der neue Stern 
neben dem alten Stern erscheinen.

Sterne die nah beieinander sind, gehören zusammen!

Klick auf einen Stern und du siehst alle verwandten Sterne leuchten!"

Interaktion:

1. Stern anklicken
   → Stern wird groß und hell
   → Verwandte Sterne leuchten auf
   → Verbindungen werden sichtbar

2. Stern hovern
   → Tooltip mit Titel erscheint
   → "Was ist ein Nullfeld?"

3. Cluster hovern
   → Cluster-Name erscheint
   → "Philosophie (234 Sterne)"

4. Kamera bewegen
   → Zoom: Mausrad
   → Rotate: Drag
   → Pan: Shift + Drag

Für Eltern

"Die Constellation zeigt WIE das System denkt.

Nicht nur WAS es weiß, sondern WIE es Wissen verknüpft.

Ähnliche Konzepte = Nahe Sterne
Themengebiete = Cluster
Verbindungen = Semantic Similarity (0-1)

Sie können sehen:
- Worüber Ihr Kind fragt (welche Cluster)
- Wie Wissen wächst (neue Sterne)
- Welche Verbindungen entstehen (Lernen)
- Wo Lücken sind (leere Bereiche)"

Praktische Nutzung:

1. "Mein Kind fragt viel über Hardware"
   → Cluster "Hardware" ist groß
   → Viele Sterne, viele Verbindungen

2. "Mein Kind versteht Philosophie nicht"
   → Cluster "Philosophie" ist klein
   → Wenige Sterne, wenige Verbindungen
   → Idee: Mehr Fragen in diesem Bereich stellen

3. "Hat das System Wissenslücken?"
   → Leere Bereiche zwischen Clustern
   → Bridges fehlen
   → Idee: Import oder neue Inhalte

Für Techniker

// Constellation API

// Get all stars
GET /api/constellation/stars
→ [
    {
        id: "embedding_001",
        position: [0.2, 0.5, 0.8],
        cluster: 0,
        metadata: {
            title: "Was ist Nullfeld?",
            type: "question",
            date: "2026-01-20"
        }
    },
    // ... 5.000 stars
]

// Get clusters
GET /api/constellation/clusters
→ [
    {
        id: 0,
        name: "Philosophie",
        center: [0.1, 0.4, 0.7],
        radius: 0.3,
        size: 234
    },
    // ... clusters
]

// Get connections
GET /api/constellation/connections
→ [
    {
        from: "embedding_001",
        to: "embedding_035",
        strength: 0.92
    },
    // ... connections
]

// Search in constellation
POST /api/constellation/search
{
    "query": "nullfeld",
    "limit": 10
}
→ [nearest 10 stars to query]

🎮 Interaktive Features

1. Live Search

// Search input
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', (e) => {
    const query = e.target.value;

    if (query.length < 3) return;

    // Highlight matching stars
    fetch('/api/constellation/search', {
        method: 'POST',
        body: JSON.stringify({ query })
    })
    .then(res => res.json())
    .then(results => {
        highlightStars(results);
    });
});

function highlightStars(results) {
    // Reset all stars
    stars.forEach(star => {
        star.material.opacity = 0.3;
        star.material.size = 0.05;
    });

    // Highlight matches
    results.forEach((result, i) => {
        const star = stars[result.id];
        star.material.opacity = 1.0;
        star.material.size = 0.1 * (1 - i * 0.1);  // Größer = relevanter
    });
}

2. Cluster Navigation

// Cluster buttons
const clusterButtons = document.getElementById('clusters');

clusters.forEach(cluster => {
    const button = document.createElement('button');
    button.textContent = `${cluster.name} (${cluster.size})`;
    button.onclick = () => {
        // Fly camera to cluster
        flyToPosition(cluster.center, cluster.radius * 2);

        // Highlight cluster stars
        highlightCluster(cluster.id);
    };
    clusterButtons.appendChild(button);
});

function flyToPosition(target, distance) {
    const duration = 1000;  // 1 second
    const start = Date.now();
    const initialPos = camera.position.clone();

    function animate() {
        const elapsed = Date.now() - start;
        const progress = Math.min(elapsed / duration, 1);

        // Smooth easing
        const ease = progress * (2 - progress);

        camera.position.lerpVectors(
            initialPos,
            new THREE.Vector3(...target).add(
                new THREE.Vector3(0, 0, distance)
            ),
            ease
        );

        if (progress < 1) {
            requestAnimationFrame(animate);
        }
    }
    animate();
}

3. Time Travel

// Timeline slider
const timeline = document.getElementById('timeline');
timeline.addEventListener('input', (e) => {
    const timestamp = parseInt(e.target.value);

    // Show only stars before timestamp
    stars.forEach(star => {
        if (star.metadata.ts <= timestamp) {
            star.visible = true;
        } else {
            star.visible = false;
        }
    });

    // Update label
    document.getElementById('timeline-label').textContent = 
        new Date(timestamp * 1000).toLocaleDateString();
});

// Result: Watch knowledge grow over time! ✨

4. Resonanz-Modus

// Click on star
stars.forEach(star => {
    star.onClick = () => {
        // Find connected stars
        const connected = getConnectedStars(star.id, 0.7);  // threshold

        // Fade out unconnected
        stars.forEach(s => {
            if (s.id === star.id || connected.includes(s.id)) {
                s.material.opacity = 1.0;
            } else {
                s.material.opacity = 0.1;
            }
        });

        // Show connections
        connections
            .filter(c => c.from === star.id || c.to === star.id)
            .forEach(c => {
                c.line.material.opacity = c.strength;
                c.line.visible = true;
            });
    };
});

📊 Beispiel-Visualisierungen

Beispiel 1: Frischer Import

Nach Import (5.000 Posts):

🌌 Große Cluster:
   - Hardware (567 Sterne)
   - Philosophie (234 Sterne)
   - Programming (445 Sterne)

🌌 Kleine Cluster:
   - Art (23 Sterne)
   - Music (12 Sterne)

📊 Analyse:
   → System kennt viel Hardware & Code
   → Wenig Kunst & Musik
   → Idee: Mehr Import oder Fokus verschieben

Beispiel 2: Nach 6 Monaten Nutzung

Original Import + 6 Monate Fragen:

🌌 Gewachsene Cluster:
   - Hardware (567 → 892 Sterne)  +57%
   - Philosophie (234 → 489 Sterne)  +109%!

🌌 Neue Cluster:
   - Spiele (67 Sterne)  NEU!
   - Geschichten (45 Sterne)  NEU!

📊 Analyse:
   → Kinder fragen viel Philosophie!
   → Neues Interesse: Spiele
   → System wächst organisch ✨

Beispiel 3: Bridges entstehen

Original: Getrennte Cluster

🌌 Philosophie        🌌 Hardware
   ⭐⭐⭐                ⭐⭐⭐
   ⭐⭐⭐                ⭐⭐⭐

(Keine Verbindung)

Nach Fragen:

🌌 Philosophie  ━━━━━  🌌 Hardware
   ⭐⭐⭐                ⭐⭐⭐
   ⭐⭐⭐                ⭐⭐⭐

Bridge: "Warum ist FPGA wie Nullfeld?"
        (Philosophie trifft Hardware!)

📊 Analyse:
   → Kind verknüpft Konzepte!
   → Interdisziplinäres Denken ✨
   → System lernt Zusammenhänge

🔬 Technische Details

Datenstruktur

// constellation_data.json
{
    "stars": [
        {
            "id": "embedding_001",
            "position": [0.234, 0.567, 0.891],
            "cluster": 0,
            "metadata": {
                "title": "Was ist Nullfeld?",
                "type": "question",
                "ts": 1737481234.567,
                "author": "kid_01",
                "tags": ["philosophie", "nullfeld"],
                "content_preview": "Das Nullfeld ist..."
            }
        },
        // ... 5.000 stars
    ],

    "clusters": [
        {
            "id": 0,
            "name": "Philosophie",
            "color": "#8B4FFF",
            "center": [0.123, 0.456, 0.789],
            "radius": 0.342,
            "size": 234
        },
        // ... clusters
    ],

    "connections": [
        {
            "from": "embedding_001",
            "to": "embedding_035",
            "strength": 0.923
        },
        // ... connections
    ],

    "metadata": {
        "generated_at": "2026-01-22T20:00:00Z",
        "total_points": 5000,
        "total_clusters": 8,
        "avg_cluster_size": 625,
        "pca_explained_variance": 0.87
    }
}

Generierung

#!/usr/bin/env python3
"""
generate_constellation.py

Generiert constellation_data.json aus Qdrant
"""

from qdrant_client import QdrantClient
from sklearn.decomposition import PCA
from sklearn.cluster import DBSCAN
import numpy as np
import json

def generate_constellation(collection_name: str):
    """Generate constellation data"""

    qdrant = QdrantClient("http://localhost:6333")

    # 1. Get all vectors
    print("📥 Fetching vectors...")
    result = qdrant.scroll(
        collection_name=collection_name,
        limit=10000,  # Max
        with_vectors=True
    )
    points = result[0]

    # 2. Extract vectors and metadata
    vectors = np.array([p.vector for p in points])
    metadata = [p.payload for p in points]

    print(f"✅ Got {len(vectors)} vectors")

    # 3. Reduce to 3D
    print("🔄 Reducing to 3D...")
    pca = PCA(n_components=3)
    positions_3d = pca.fit_transform(vectors)

    print(f"✅ Explained variance: {pca.explained_variance_ratio_.sum():.2f}")

    # 4. Cluster
    print("🔍 Clustering...")
    clustering = DBSCAN(eps=0.3, min_samples=5).fit(positions_3d)

    unique_labels = set(clustering.labels_)
    unique_labels.discard(-1)  # Remove noise

    print(f"✅ Found {len(unique_labels)} clusters")

    # 5. Build stars
    stars = []
    for i, (pos, meta, label) in enumerate(zip(positions_3d, metadata, clustering.labels_)):
        stars.append({
            "id": f"embedding_{i:06d}",
            "position": pos.tolist(),
            "cluster": int(label) if label != -1 else None,
            "metadata": meta
        })

    # 6. Build clusters
    clusters = []
    for label in unique_labels:
        cluster_points = positions_3d[clustering.labels_ == label]
        center = cluster_points.mean(axis=0)
        radius = np.max(np.linalg.norm(cluster_points - center, axis=1))

        clusters.append({
            "id": int(label),
            "name": f"Cluster {label}",  # TODO: Auto-name
            "color": get_color(label),
            "center": center.tolist(),
            "radius": float(radius),
            "size": len(cluster_points)
        })

    # 7. Build connections (top similarity pairs)
    print("🔗 Building connections...")
    connections = []
    for i in range(len(vectors)):
        # Find nearest neighbors
        distances = np.linalg.norm(vectors - vectors[i], axis=1)
        nearest = np.argsort(distances)[1:6]  # Top 5 (skip self)

        for j in nearest:
            similarity = 1 - distances[j]
            if similarity > 0.7:  # Threshold
                connections.append({
                    "from": f"embedding_{i:06d}",
                    "to": f"embedding_{j:06d}",
                    "strength": float(similarity)
                })

    print(f"✅ Found {len(connections)} connections")

    # 8. Save
    output = {
        "stars": stars,
        "clusters": clusters,
        "connections": connections,
        "metadata": {
            "generated_at": datetime.now().isoformat(),
            "total_points": len(stars),
            "total_clusters": len(clusters),
            "avg_cluster_size": np.mean([c['size'] for c in clusters]),
            "pca_explained_variance": float(pca.explained_variance_ratio_.sum())
        }
    }

    with open('constellation_data.json', 'w') as f:
        json.dump(output, f, indent=2)

    print("✅ Saved to constellation_data.json")

if __name__ == "__main__":
    generate_constellation("wald_knowledge")

🎯 Use Cases

1. Discovery

Problem: Kind weiß nicht was es fragen soll

Lösung:

1. Öffne Constellation
2. Zeige Cluster-Übersicht
3. Kind wählt interessanten Cluster
4. Klick → Verwandte Sterne leuchten
5. Kind entdeckt neue Fragen!

2. Learning Path

Problem: Wie lernt man ein Thema?

Lösung:

1. Finde Start-Stern (z.B. "Was ist FPGA?")
2. Folge Verbindungen
3. Nächster Stern = Nächste Frage
4. Learning Path = Pfad durch Sterne!

3. Quality Check

Problem: Ist der Vektor gut?

Lösung:

Schaue Constellation:

🟢 GUT:
   - Viele kleine Cluster
   - Gleichmäßige Verteilung
   - Viele Verbindungen

🔴 SCHLECHT:
   - Ein großer Blob
   - Ungleiche Verteilung
   - Wenige Verbindungen

🚀 Zusammenfassung

Die Constellation ist:

Visualisierung des Vektors
Navigation durch Wissen
Discovery Tool für Kinder
Quality Check für System
Learning Path Generator
Community Insight (was fragen andere?)

Nicht:
❌ Nur Deko
❌ Nur für Techniker
❌ Statisch

Sondern:
✅ Lebendig
✅ Interaktiv
✅ Wachsend
✅ Für alle

Die Sternenkarte zeigt:
Der Wald ist nicht nur Code.
Der Wald ist eine Landschaft.
Eine Landschaft aus Wissen.
Eine Landschaft die wächst.
Mit jedem Stern.
Mit jeder Frage.

Wuuuhuuuu! 🌌✨


Version: 1.0
Lizenz: CKL
Live: https://crumbforest.194-164-194-191.sslip.io/constellation/
Status: Leuchtet ✨