🌌 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 ✨