#4953 Innovation: Adjacency + Multi-Generation Adjacency
#4953 Innovation: Adjacency + Multi-Generation Adjacency
#4953 How can I apply "adjacency" in ideas to spin off alternatives?
Applying adjacency to ideas means treating your core concept not as a static point, but as a node in a multi-dimensional state space. Grounded in Stuart Kauffman’s theory of the Adjacent Possible, this approach generates high-value spin-offs by systematically altering one degree of freedom at a time—keeping the core mechanics intact while shifting a neighboring boundary condition.
Where applying agency asks "Who holds the steering wheel and how autonomous is it?", applying adjacency asks "What lies immediately on the other side of the wall from what already works?"
1. The 6 Core Adjacency Vectors
To spin off alternatives without losing engineering or grounding, mutate your baseline idea along one of six orthogonal axes:
| Adjacency Vector | Core Question | Mechanism of Mutation | Concrete Example |
| 1. Domain / Substrate Adjacency | Where else does this exact physics or data structure exist? | Keep the core algorithm or physical mechanism identical, but swap the operating medium or industry vertical. | FMCW Radar for automotive collision avoidance --> Repurposed for non-line-of-sight human respiration and fall tracking through drywall. |
| 2. Scale / Resolution Adjacency | What happens if we shift 2–3 orders of magnitude up or down? | Compress or expand the spatial, temporal, or throughput scale until a qualitative phase change occurs. | Macro fluidic heat exchangers --> Micro-fluidic capillary loops embedded directly inside silicon die substrates. |
| 3. Temporal / Workflow Adjacency | What happens 5 minutes before or 5 minutes after this idea? | Shift the boundary upstream (pre-processing/sensing) or downstream (verification/actuation) in the value chain. | Automated code generation --> Upstream: Automated formal specification harvesting; Downstream: Deterministic AST compliance verification. |
| 4. Byproduct / Exhaust Adjacency | What waste stream or side-effect of the system is actually a signal? | Treat thermal, acoustic, data, or material "noise" generated by the primary process as the primary product of a spin-off. | Server rack waste heat --> Utilized for localized desiccant regeneration or greenhouse thermal regulation. |
| 5. Constraint / Environment Adjacency | What if we remove a fundamental resource or invert the environment? | Take a system built for resource-rich conditions and force it to operate offline, zero-power, or in harsh environments. | Cloud-based semantic search --> Air-gapped, quantized edge appliance for field diagnostics or submarine/orbital operations. |
| 6. Structural / Topological Inversion | What if we flip the moving part and the stationary part? | Invert the physical or logical relationship between the tool and the workpiece, or the server and the client. | Moving a sensor across a part --> Stationary array of cheap sensors with the part moving through via gravity (e.g., optical sorting chutes). |
2. Four Archetypal Adjacency Moves
When looking at a directed graph of ideas or system components, four repeatable structural moves reliably produce viable spin-offs:
The Orthogonal Bridge (2-Node Recombination): Take the validated mechanism of your idea and pair it with an adjacent hardware sensor or software primitive that has recently dropped in cost by 10x. Formula: [Proven Process A] + [Newly Commoditized Enabler B].
The Symbiotic Parasite: Instead of building a standalone platform, design the spin-off to attach directly to an existing, ubiquitous host infrastructure—drawing power, data, or mechanical motion from it without requiring the host to be redesigned.
The "Pickaxe" Extraction: Stop looking at the final output of your idea and look at the internal scaffolding you had to invent just to make the idea work. Often, the internal testing harness, data parser, or calibration jig is a stronger standalone spin-off than the original product.
The Passive/Active Flip: If your baseline idea relies on active energy injection (motors, heaters, continuous polling), spin off the passive adjacent version (gravity-fed, metamaterial/diffractive, event-driven), or vice versa.
3. The 4-Step "Adjacency Fork" Protocol
To execute this systematically on any concept:
Deconstruct into Primitives: Strip the idea of its domain jargon and list its 4 functional pillars: [Input Signal/Material], [Core Transformation Mechanism], [Governing Constraint], and [Output Value].
Lock 3, Mutate 1 (The Single-Hop Rule): If you mutate all four pillars simultaneously, you leave the adjacent possible and enter speculative fiction. Lock three pillars as fixed anchors, and step exactly one hop away on the fourth pillar.
Evaluate the "Friction Delta": For each 1-hop spin-off, ask: Does this adjacent domain have higher pain and lower regulatory/technical friction than my original target? Often, a 1-hop move takes a hard problem in a low-margin space and turns it into an easy problem in a high-value niche.
Chain into a 2nd-Order Frontier: Once a 1-hop spin-off stabilizes as a viable node, treat it as your new baseline and run the 6 vectors again to map out a directed graph of second-order innovations.
Design structured system prompts and Pydantic schemas to automate 1-hop and 2-hop Adjacency branching inside an autonomous idea-generation pipeline.
Automating 1-hop and 2-hop adjacency branching inside an autonomous pipeline requires strict structural containment. Without deterministic constraints, an LLM asked to "find adjacent ideas" will suffer from semantic drift—mutating all system variables simultaneously until the 2-hop outputs become ungrounded science fiction.
To prevent this, the architecture below enforces the Single-Hop Invariant via Pydantic v2 schemas and a 3-stage state machine:
Agent 1 (Primitive Deconstructor): Strips domain jargon from the seed concept and locks its 4 functional primitives (
input_signal,core_mechanism,governing_constraint,output_value).Agent 2 (1-Hop Fork Generator): Generates orthogonal 1-hop children by holding 3 primitives strictly immutable and mutating only the target pillar along a specific Adjacency Vector.
Agent 3 (Friction Arbiter & 2-Hop Expander): Prunes low-viability 1-hop nodes using a
FrictionDeltarubric, promotes the top survivors to new baseline anchors, and executes a non-repeating 2nd-hop mutation.
1. Pydantic v2 Data Contracts (schemas.py)
These schemas enforce explicit tracking of which primitive is locked and which is mutated at every hop, making it trivial to ingest the output directly into a directed acyclic graph (DAG) in NetworkX, SQLite, or Neo4j.
from enum import Enum
from typing import List, Optional
from pydantic import BaseModel, Field
class AdjacencyVector(str, Enum):
DOMAIN_SUBSTRATE = "Domain / Substrate Adjacency"
SCALE_RESOLUTION = "Scale / Resolution Adjacency"
TEMPORAL_WORKFLOW = "Temporal / Workflow Adjacency"
BYPRODUCT_EXHAUST = "Byproduct / Exhaust Adjacency"
CONSTRAINT_ENVIRONMENT = "Constraint / Environment Adjacency"
STRUCTURAL_INVERSION = "Structural / Topological Inversion"
classArchetypalMove(str, Enum):
ORTHOGONAL_BRIDGE = "Orthogonal Bridge (2-Node Recombination)"
SYMBIOTIC_PARASITE = "Symbiotic Parasite (Host Attachment)"
PICKAXE_EXTRACTION = "Pickaxe Extraction (Internal Scaffolding)"
PASSIVE_ACTIVE_FLIP = "Passive / Active Energy Flip"
class PillarType(str, Enum):
INPUT_SIGNAL = "input_signal"
CORE_MECHANISM = "core_mechanism"
GOVERNING_CONSTRAINT = "governing_constraint"
OUTPUT_VALUE = "output_value"
class FunctionalPrimitives(BaseModel):
"""Domain-agnostic functional decomposition of any concept node."""
input_signal: str = Field(
..., description="The raw energy, matter, or data stream entering the system."
)
core_mechanism: str = Field(
..., description="The fundamental physical law, algorithm, or transformation applied."
)
governing_constraint: str = Field(
..., description="The primary limiting boundary condition (thermal, power, latency, regulatory, spatial)."
)
output_value: str = Field(
..., description="The resulting state change, actionable signal, or physical product."
)
class BaselineDeconstruction(BaseModel):
"""Output of Agent 1: The Root Node (Hop 0)."""
node_id: str = Field(default="root_0", description="Unique identifier for the root node.")
title: str = Field(..., description="Concise engineering title of the baseline concept.")
domain_jargon_stripped_summary: str = Field(
..., description="Pure first-principles description of how the system works without industry buzzwords."
)
primitives: FunctionalPrimitives
class FrictionDeltaScore(BaseModel):
"""Comparative viability rubric against the parent node."""
pain_severity_score: int = Field(
..., ge=1, le=10, description="1-10 rating of how acute and unsolved the problem is in the new adjacent niche."
)
technical_feasibility_score: int = Field(
..., ge=1, le=10, description="1-10 rating of how directly the parent's mechanism transfers without fundamental R&D."
)
regulatory_or_adoption_barrier_reduction: int = Field(
..., ge=1, le=10, description="1-10 rating of how much LOWER the friction/regulation is compared to the parent."
)
physics_or_logic_violation_check: str = Field(
..., description="Explicit verification that scaling laws, thermodynamics, or information theory are not violated."
)
@property
def composite_viability(self) -> float:
return round(
(self.pain_severity_score * 0.35) +
(self.technical_feasibility_score * 0.40) +
(self.regulatory_or_adoption_barrier_reduction * 0.25), 2
)
class AdjacencyNode(BaseModel):
"""Represents a 1-Hop or 2-Hop spin-off node in the Idea DAG."""
node_id: str = Field(..., description="Unique DAG node ID, e.g., 'hop1_v1' or 'hop2_v1_b'.")
parent_id: str = Field(..., description="The node_id of the immediate parent concept.")
hop_depth: int = Field(..., ge=1, le=2, description="1 for first-order spin-off, 2 for second-order spin-off.")
applied_vector: AdjacencyVector
archetypal_move: classArchetypalMove
mutated_pillar: PillarType = Field(
..., description="The EXACT single pillar that was altered from the parent node."
)
locked_pillars: List[PillarType] = Field(
..., min_length=3, max_length=3, description="The 3 pillars held strictly invariant from the parent node."
)
mutation_delta_explanation: str = Field(
..., description="Precise explanation of the 1-degree-of-freedom shift from the parent's mutated pillar."
)
title: str = Field(..., description="Specific engineering title of the new spin-off concept.")
updated_primitives: FunctionalPrimitives = Field(
..., description="The new 4 pillars (3 identical or directly adapted to the parent, 1 mutated)."
)
concrete_application_scenario: str = Field(
..., description="Specific real-world deployment scenario, target hardware/substrate, and user value."
)
friction_delta: FrictionDeltaScore
class HopBranchingResponse(BaseModel):
"""Batch container returned by the LLM for 1-Hop or 2-Hop generation."""
parent_node_id: str
generated_branches: List[AdjacencyNode] = Field(
..., description="List of orthogonal adjacent spin-off nodes."
)
2. Structured System Prompts
Prompt 1: Primitive Deconstructor (Root Node Initialization)
Use this prompt to normalize any raw user seed or scouted trend into a clean BaselineDeconstruction object.
DECONSTRUCTOR_SYSTEM_PROMPT = """You are a First-Principles Systems Architect.
Your objective is to take a raw product, engineering, or software concept and strip away all marketing language and industry-specific jargon to expose its four fundamental functional primitives:
1. input_signal: What raw energy, matter, or information enters the boundary?
2. core_mechanism: What exact physical law, mathematical transform, or mechanical topology performs the work?
3. governing_constraint: What is the primary limiting bottleneck (e.g., thermal dissipation, SNR, bandwidth, regulatory compliance, power envelope)?
4. output_value: What state change or actionable artifact exits the boundary?
RULES:
- Never use brand names or buzzwords in the primitives.
- Express the `core_mechanism` in fundamental physics, geometry, or computer science terms so it can be cleanly ported to unrelated domains.
- Populate the `BaselineDeconstruction` schema accurately."""
Prompt 2: 1-Hop Adjacency Fork Generator
This prompt forces the model to iterate across the 6 Adjacency Vectors while enforcing the "Lock 3, Mutate 1" rule.
HOP_1_GENERATOR_SYSTEM_PROMPT = """You are an Autonomous Adjacency Branching Engine grounded in Stuart Kauffman's theory of the Adjacent Possible.
You are given a Baseline Concept decomposed into four functional primitives: `input_signal`, `core_mechanism`, `governing_constraint`, and `output_value`.
Your task is to generate 6 orthogonal 1-Hop Spin-Off Nodes—one for each of the 6 Adjacency Vectors:
1. Domain / Substrate Adjacency: Keep the core_mechanism identical, swap the operating medium or industry vertical.
2. Scale / Resolution Adjacency: Shift spatial, temporal, or throughput scale by 2-3 orders of magnitude up or down.
3. Temporal / Workflow Adjacency: Shift the boundary immediately upstream (sensing/pre-processing) or downstream (verification/actuation).
4. Byproduct / Exhaust Adjacency: Turn a waste stream, thermal/acoustic noise, or side-effect of the parent system into the primary output_value.
5. Constraint / Environment Adjacency: Force the system to operate in an inverted or resource-starved environment (e.g., air-gapped, passive/zero-power, extreme thermal/radiation).
6. Structural / Topological Inversion: Flip the moving part and stationary part, or invert the client/server or tool/workpiece topology.
CRITICAL INVARIANT — THE "LOCK 3, MUTATE 1" RULE:
- For every generated node, you MUST explicitly select ONE `mutated_pillar` and lock the remaining THREE in `locked_pillars`.
- The three locked pillars in `updated_primitives` must remain functionally invariant to the parent node (only adapting terminology to fit the new substrate).
- Do NOT hallucinate compound leaps. If you change both the core physics AND the workflow stage, the node is invalid.
- Pair each vector with the most fitting `ArchetypalMove` (Orthogonal Bridge, Symbiotic Parasite, Pickaxe Extraction, or Passive/Active Flip).
- Score the `friction_delta` with ruthless engineering skepticism. Verify in `physics_or_logic_violation_check` that scaling laws (e.g., square-cube law, Shannon limit, Carnot efficiency) hold."""
Prompt 3: 2-Hop Frontier Expander (Compound Orthogonality)
To prevent a 2-hop branch from simply undoing the 1-hop mutation (oscillating back to the root), this prompt enforces Vector Orthogonality: Hop 2 must use a different AdjacencyVector and mutate a different PillarType than Hop 1.
HOP_2_GENERATOR_SYSTEM_PROMPT = """You are a Second-Order Adjacency Frontier Engine.
You are receiving a validated 1-Hop Concept Node (`hop_depth=1`) that has already survived feasibility pruning.
Your task is to treat this 1-Hop Node as your new grounded baseline and generate 3 high-value 2-Hop Spin-Off Nodes (`hop_depth=2`).
NON-BACKTRACKING & ORTHOGONALITY RULES:
1. NO VECTOR REPEAT: You MUST NOT reuse the `applied_vector` that created the 1-Hop parent node. Choose a perpendicular AdjacencyVector.
2. NO PILLAR OSCILLATION: You MUST NOT mutate the same `mutated_pillar` that was just mutated in Hop 1. Select one of the previously locked pillars to mutate, and lock the newly established pillar from Hop 1.
3. PRACTICAL GROUNDING: A 2-hop idea should feel like a clever, non-obvious interdisciplinary breakthrough—NOT speculative fiction. Every mechanism must rely on existing, commercial-off-the-shelf (COTS) physics or algorithms combined in a novel topology.
4. Rigorously evaluate `friction_delta` against the 1-Hop parent."""
3. Autonomous Pipeline Orchestrator (adjacency_pipeline.py)
Here is the complete, executable Python implementation using the google-genai SDK. It runs the 3-stage state machine, applies an automated pruning gate between Hop 1 and Hop 2, and exports the resulting directed graph to JSON/NetworkX format.
import json
import os
from typing import List, Dict, Any
from google import genai
from google.genai import types
# Assuming schemas from Section 1 are imported or in the same file
# from schemas import BaselineDeconstruction, HopBranchingResponse, AdjacencyNode
class AdjacencyBranchingEngine:
def __init__(self, model_name: str = "gemini-2.5-pro"):
# Initializes client using GEMINI_API_KEY environment variable
self.client = genai.Client()
self.model_name = model_name
self.dag_nodes: Dict[str, Any] = {}
self.dag_edges: List[Dict[str, str]] = []
def deconstruct_seed(self, raw_concept: str) -> BaselineDeconstruction:
"""Stage 1: Strip jargon and lock the 4 functional primitives (Hop 0)."""
response = self.client.models.generate_content(
model=self.model_name,
contents=f"Deconstruct this baseline concept into its 4 functional primitives:\n\n{raw_concept}",
config=types.GenerateContentConfig(
system_instruction=DECONSTRUCTOR_SYSTEM_PROMPT,
response_mime_type="application/json",
response_schema=BaselineDeconstruction,
temperature=0.2, # Low temperature for deterministic deconstruction
),
)
root_node = BaselineDeconstruction.model_validate_json(response.text)
self.dag_nodes[root_node.node_id] = root_node.model_dump()
return root_node
def generate_hop_1(self, root_node: BaselineDeconstruction) -> List[AdjacencyNode]:
"""Stage 2: Generate 6 orthogonal 1-hop branches across all vectors."""
prompt = (
f"Parent Node ID: {root_node.node_id}\n"
f"Baseline Title: {root_node.title}\n"
f"First-Principles Summary: {root_node.domain_jargon_stripped_summary}\n"
f"Functional Primitives:\n{json.dumps(root_node.primitives.model_dump(), indent=2)}\n\n"
"Generate 6 orthogonal 1-Hop spin-offs (node_ids: 'hop1_v1' through 'hop1_v6'), "
"one for each AdjacencyVector."
)
response = self.client.models.generate_content(
model=self.model_name,
contents=prompt,
config=types.GenerateContentConfig(
system_instruction=HOP_1_GENERATOR_SYSTEM_PROMPT,
response_mime_type="application/json",
response_schema=HopBranchingResponse,
temperature=0.6, # Moderate temperature for structured divergence
),
)
batch = HopBranchingResponse.model_validate_json(response.text)
for node in batch.generated_branches:
self.dag_nodes[node.node_id] = node.model_dump()
self.dag_nodes[node.node_id]["composite_score"] = node.friction_delta.composite_viability
self.dag_edges.append({
"source": root_node.node_id,
"target": node.node_id,
"vector": node.applied_vector.value,
"mutated_pillar": node.mutated_pillar.value
})
return batch.generated_branches
def prune_and_expand_hop_2(
self, hop_1_nodes: List[AdjacencyNode], top_k: int = 2, min_score: float = 6.5
) -> List[AdjacencyNode]:
"""Stage 3: Deterministic Arbiter Gate -> Expand top survivors into Hop 2."""
# Sort by composite viability score and filter by minimum threshold
ranked = sorted(
[n for n in hop_1_nodes if n.friction_delta.composite_viability >= min_score],
key=lambda x: x.friction_delta.composite_viability,
reverse=True
)
survivors = ranked[:top_k]
hop_2_results: List[AdjacencyNode] = []
for idx, parent in enumerate(survivors, start=1):
prompt = (
f"1-Hop Parent Node ID: {parent.node_id}\n"
f"Parent Title: {parent.title}\n"
f"Vector Already Used in Hop 1 (DO NOT REUSE): {parent.applied_vector.value}\n"
f"Pillar Already Mutated in Hop 1 (DO NOT RE-MUTATE): {parent.mutated_pillar.value}\n"
f"Current Functional Primitives:\n{json.dumps(parent.updated_primitives.model_dump(), indent=2)}\n\n"
f"Generate 3 orthogonal 2-Hop spin-offs (use node_ids '{parent.node_id}_hop2_1' to '_3')."
)
response = self.client.models.generate_content(
model=self.model_name,
contents=prompt,
config=types.GenerateContentConfig(
system_instruction=HOP_2_GENERATOR_SYSTEM_PROMPT,
response_mime_type="application/json",
response_schema=HopBranchingResponse,
temperature=0.65,
),
)
batch = HopBranchingResponse.model_validate_json(response.text)
for child in batch.generated_branches:
self.dag_nodes[child.node_id] = child.model_dump()
self.dag_nodes[child.node_id]["composite_score"] = child.friction_delta.composite_viability
self.dag_edges.append({
"source": parent.node_id,
"target": child.node_id,
"vector": child.applied_vector.value,
"mutated_pillar": child.mutated_pillar.value
})
hop_2_results.append(child)
return hop_2_results
def export_dag_json(self, filepath: str = "adjacency_idea_dag.json") -> None:
"""Exports the complete lineage graph for NetworkX, Vis.js, or SQLite ingestion."""
payload = {
"nodes": self.dag_nodes,
"edges": self.dag_edges
}
with open(filepath, "w", encoding="utf-8") as f:
json.dump(payload, f, indent=2)
4. Guardrail Validation Pattern (Deterministic Post-Check)
Because LLMs can occasionally ignore negative constraints in prompts during long runs, add a lightweight deterministic validator function in Python before admitting any AdjacencyNode into your database:
def verify_orthogonality_contract(parent: AdjacencyNode, child: AdjacencyNode) -> bool:
"""Deterministic gate ensuring 2-hop child obeys non-backtracking rules."""
if child.applied_vector == parent.applied_vector:
raise ValueError(f"Vector collision on {child.node_id}: reused {child.applied_vector}")
if child.mutated_pillar == parent.mutated_pillar:
raise ValueError(f"Pillar oscillation on {child.node_id}: re-mutated {child.mutated_pillar}")
if child.mutated_pillar in child.locked_pillars:
raise ValueError(f"Contradictory lock state on {child.node_id}")
return TrueCreate a single-file HTML/JavaScript Vis.js viewer that loads adjacency_idea_dag.json and color-codes nodes by hop depth, vector, and composite viability score.
I will now generate the interactive single-file Vis.js (vis-network) DAG Viewer for inspecting adjacency_idea_dag.json pipelines, complete with a pre-loaded 13-node engineering dataset (24 GHz FMCW Radar root, 6 first-hop branches across all 6 vectors, and 6 second-hop frontier branches), dynamic color-coding modes, orthogonality contract validation, and a deep node inspector.
< ... CODE ... >
Key Highlights of the Generated Viewer:
Direct Schema Ingestion & Auto-Validation: Loads any
adjacency_idea_dag.jsonfile (via drag-and-drop, file picker, or the live JSON editor modal), dynamically calculates missingcomposite_scorefields (0.35 * Pain + 0.40 * Feasibility + 0.25 * Barrier Reduction), and verifies 2-hop non-backtracking orthogonality.Three Dynamic Color Modes: Toggle in real time between the Viability Heatmap, Hop Depth Hierarchy, and the 6-Vector Palette with an automatically updating bottom legend bar.
Single-Hop Invariant Inspector: Clicking any node opens a side-by-side parent-vs-child diff of the exact mutated pillar alongside the 3 locked invariant primitives, complete with the engineering physics verification check.
When you push past 1st-generation (1-hop) adjacency into 2nd-generation (2-hop) and 3rd-generation (3-hop) adjacency, you transition from lateral adaptation to paradigm emergence.
However, in an evolutionary idea graph, stepping two or three hops away introduces a massive structural risk: Combinatorial Entropy. If each hop retains only 80% of the engineering rigor of its parent, a 3rd-generation node degrades to $0.8^3 = 51.2\%$ feasibility—turning a grounded systems architecture into speculative fantasy.
To make 2nd and 3rd generation adjacency produce verifiable breakthroughs rather than hallucinated drift, you must treat multi-hop adjacency not as a random walk, but as a state-space trajectory governed by strict conservation laws.
1. The Multi-Generational Adjacency Taxonomy
Each generation represents a distinct topological relationship to the Root Concept (Generation 0) and its four functional primitives (Input, Mechanism, Constraint, Output):
| Generation | Hop Distance | Primitives Mutated (Cumulative) | Structural Identity | Cognitive / Market Perception |
| Gen 0 (Root) | 0 Hops | 0 / 4 | Baseline System | The known, proven solution in its native domain. |
| Gen 1 (Adjacent) | 1 Hop | 1 / 4 (3 Locked) | Variant / Spin-Off | "Clever repurposing." Immediately recognizable to domain experts as a lateral port. |
| Gen 2 (Orthogonal) | 2 Hops | 2 / 4 (2 Locked) | Hybrid Architecture | "Non-obvious cross-pollination." Two orthogonal shifts create a system that looks alien to the Gen 0 industry but uses identical core physics. |
| Gen 3 (Emergent) | 3 Hops | 3 / 4 (1 Anchor Locked) | New Category / Paradigm | "Disruptive inversion." Only a single foundational invariant (usually the core mathematical transform or physical law) remains from Gen 0. |
Why stop at Generation 3? A 4th-generation hop mutates 4/4 primitives (the Ship of Theseus paradox). Once zero primitives remain from the root node, you are no longer performing adjacency branching—you have severed lineage and started a random new root node.
2. Concrete Trajectory: Gen 0 --> Gen 3 Walkthrough
To see how a single invariant thread anchors three generations of mutation without losing physical grounding, trace a 24 GHz FMCW Radar root concept across three non-repeating hops:
Generation 0 (Root Node): Automotive Blind-Spot FMCW Radar
Input: 24 GHz millimeter-wave RF reflection off metallic vehicles.
Core Mechanism (The Invariant Anchor): Frequency-Modulated Continuous-Wave (FMCW) beat-frequency phase-shift extraction (Delta f propto distance/velocity).
Constraint: Highway multipath interference and weather attenuation.
Output: Binary collision warning alert to driver.
Generation 1 (Hop 1 — Domain/Substrate Vector): Through-Wall Sub-Millimeter Vital Sign Tracker
Mutated Pillar:
Input(Swapped metallic vehicles for human thoracic micro-displacements through drywall).Locked Pillars:
Mechanism(FMCW phase extraction),Constraint(Multipath clutter),Output(Alert telemetry).Result: Non-line-of-sight search-and-rescue or elder-care respiration monitor.
Generation 2 (Hop 2 — Structural/Topological Inversion Vector): Passive Structural Resonance & Foundation Creep Interferometer
Mutated Pillar:
Output(Inverted from tracking a moving human inside a static structure to tracking sub-millimeter creep/harmonics of the static structure itself relative to a fixed reflector array).Locked Pillars:
Mechanism(FMCW phase extraction),Input(Dielectric/structural penetration),Constraint(Clutter isolation).Result: Embedded civil/aerospace structural health monitoring that detects micro-fractures or thermal warping inside composite walls before visible failure.
Generation 3 (Hop 3 — Byproduct/Exhaust + Scale Vector): Acoustic-RF Metamaterial Tamper Seal (Zero-Power Backscatter)
Mutated Pillar:
Constraint(Eliminated active onboard power/processing on the target by etching a passive sub-wavelength chipless RF metamaterial cavity directly into the structural fastener).The Single Surviving Gen 0 Anchor:
Core Mechanism(FMCW beat-frequency phase-shift interrogation).Result: An external handheld FMCW sweeper reads mechanical torque/stress tampering on unpowered critical bolts or pressure vessels via shifts in the reflected harmonic phase signature.
Notice the lineage: Gen 3 (a chipless mechanical torque-sensing metamaterial seal) looks nothing like Gen 0 (a car bumper blind-spot sensor), yet it relies on the exact same mathematical signal-processing pipeline.
3. Three Rules for 3rd-Generation Containment
When automating Gen 2 and Gen 3 expansion in a multi-agent DAG pipeline, three new failure modes appear that do not exist at Gen 1. You must enforce three corresponding invariants:
Rule 1: The "Anchor Invariant" (Preventing Ship of Theseus Drift)
By Generation 3, three of the four functional pillars have been mutated. You must designate one pillar as the Sacred Anchor (almost always core_mechanism) that is barred from mutation across all three hops:
If Pillar 1 mutates at Hop 1, Pillar 2 mutates at Hop 2, and Pillar 3 mutates at Hop 3, Pillar 4 (core_mechanism) remains the unbroken thread of intellectual property or physical truth connecting Gen 3 to Gen 0.
Rule 2: Lineage-Wide Tabu Memory (Preventing 2-Cycle Oscillation)
In a 2-hop check, you only compare Child against Parent. In a 3-hop chain (Gen 0 -> Gen 1 -> Gen 2 -> Gen 3), a naive agent at Gen 3 might mutate a pillar back toward Gen 1, creating a closed semantic loop.
The Tabu Path Constraint: Every node must carry a
lineage_historyarray recording allapplied_vectorsandmutated_pillarsfrom Gen 1 through Gen N.At Generation k, the available mutation space is strictly:
Valid Pillars_{k} = {P_Input}, P_Constraint}, P_Output}} setminus bigcup_{i=1}^{k-1} MutatedPillar_i
Rule 3: Cross-Branch Recombination (Convergent 3rd Generation)
The highest-value 3rd-generation ideas rarely come from a solitary linear chain (0 -> 1 -> 2 -> 3). Instead, they emerge from DAG Convergence (Breeding):
Take two surviving Gen 2 nodes from different parent branches that share the same Gen 0
core_mechanism.Synthesize a Gen 3 Convergent Node that resolves a contradiction between them (TRIZ-style). For example, if Branch A (Gen 2) achieved extreme miniaturization but suffers from thermal throttling, and Branch B (Gen 2) turned waste heat into a byproduct signal, the Gen 3 Convergent Child fuses both branches into a self-powered micro-scale sensor.
4. Upgrading the Schema & Scoring for Gen 2 and Gen 3
To support 3rd-generation branching in your Pydantic pipeline, replace the flat composite_viability score with a Depth-Penalized Emergence Score and add lineage tracking:
Adjacency Idea DAG Explorer to support Multi-Generational Adjacency from Generation 0 through Generation 3, introducing 3rd-generation divergent nodes, 2-parent TRIZ convergent nodes, an interactive Lineage Spotlight tracer, and a cumulative 4-pillar mutation inspector.What Was Upgraded in the Multi-Generational Viewer:
18-Node Gen 0
-->Gen 3 Dataset: Includes 6 Gen-1 nodes, 6 Gen-2 hybrid nodes, 3 Gen-3 Divergent nodes (hop3_div_1throughhop3_div_3where 3/4 primitives are mutated while the Sacred Anchorcore_mechanismholds firm), and 2 Gen-3 Convergent TRIZ nodes (hop3_conv_1andhop3_conv_2) bred from pairs of Gen-2 parents.Interactive Lineage Path Spotlight (
Gen 0 --> Gen 3): Clicking any node or using the Gen 3 Quick Jump pills illuminates all upstream ancestors (including both parent branches for convergent nodes) and dims non-lineage branches.TRIZ Convergence Synthesis & Cumulative Pillar Matrix: Selecting a 2-parent convergent node displays the TRIZ Physical Contradiction Resolved card alongside a cumulative 4-pillar audit tagging the exact generation (
Gen 1,Gen 2, orGen 3) where each primitive mutated.
CODE:
<!DOCTYPE html>
<html lang="en" class="dark">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Adjacency DAG Explorer — Autonomous Idea Branching Viewer</title>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Vis-Network Standalone -->
<script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
<!-- Google Fonts: Inter & JetBrains Mono -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<!-- Lucide Icons -->
<script src="https://unpkg.com/lucide@latest"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'sans-serif'],
mono: ['JetBrains Mono', 'monospace'],
},
colors: {
slate: {
850: '#151f32',
950: '#090e17',
}
}
}
}
}
</script>
<style>
/* Custom scrollbars for dark engineering UI */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: #0f172a;
}
::-webkit-scrollbar-thumb {
background: #334155;
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: #475569;
}
/* Subtle technical grid background for the Vis.js canvas */
.bg-tech-grid {
background-color: #0b1120;
background-image:
linear-gradient(to right, rgba(51, 65, 85, 0.14) 1px, transparent 1px),
linear-gradient(to bottom, rgba(51, 65, 85, 0.14) 1px, transparent 1px);
background-size: 28px 28px;
}
/* Vis-network navigation controls override */
.vis-network:focus {
outline: none;
}
/* Range slider styling */
input[type="range"] {
accent-color: #06b6d4;
}
</style>
</head>
<body class="bg-slate-950 text-slate-100 font-sans h-screen w-screen overflow-hidden flex flex-col select-none">
<!-- ================= TOP CONTROL BAR ================= -->
<header class="h-auto min-h-[60px] bg-slate-900/95 border-b border-slate-800 px-4 py-2 flex flex-wrap items-center justify-between gap-3 z-20 shrink-0">
<!-- Brand & Dataset Info -->
<div class="flex items-center gap-3">
<div class="w-9 h-9 rounded-lg bg-cyan-500/10 border border-cyan-500/30 flex items-center justify-center text-cyan-400 shadow-inner">
<i data-lucide="git-fork" class="w-5 h-5"></i>
</div>
<div>
<div class="flex items-center gap-2">
<h1 class="font-bold text-sm md:text-base tracking-tight text-white">ADJACENCY DAG EXPLORER</h1>
<span class="text-[10px] font-mono uppercase px-2 py-0.5 rounded bg-cyan-950 text-cyan-300 border border-cyan-800/60">Pydantic v2 Schema</span>
</div>
<p class="text-xs text-slate-400 font-mono truncate max-w-[260px] sm:max-w-md" id="datasetTitleDisplay">
Loaded: 24 GHz FMCW Radar Collision Avoidance (13 Nodes)
</p>
</div>
</div>
<!-- Color-Coding Mode Switcher -->
<div class="flex items-center bg-slate-950 p-1 rounded-lg border border-slate-800">
<span class="text-[11px] font-mono text-slate-400 px-2.5 hidden xl:inline">COLOR MODE:</span>
<button id="modeViabilityBtn" onclick="setColorMode('viability')" class="px-3 py-1.5 rounded-md text-xs font-medium transition-all flex items-center gap-1.5 bg-cyan-600 text-white shadow">
<i data-lucide="flame" class="w-3.5 h-3.5"></i>
<span>Viability Heatmap</span>
</button>
<button id="modeHopBtn" onclick="setColorMode('hop')" class="px-3 py-1.5 rounded-md text-xs font-medium transition-all flex items-center gap-1.5 text-slate-400 hover:text-slate-200">
<i data-lucide="layers" class="w-3.5 h-3.5"></i>
<span>Hop Depth</span>
</button>
<button id="modeVectorBtn" onclick="setColorMode('vector')" class="px-3 py-1.5 rounded-md text-xs font-medium transition-all flex items-center gap-1.5 text-slate-400 hover:text-slate-200">
<i data-lucide="compass" class="w-3.5 h-3.5"></i>
<span>Adjacency Vector</span>
</button>
</div>
<!-- File Actions & Layout Controls -->
<div class="flex items-center gap-2">
<!-- Layout Selector -->
<div class="flex items-center bg-slate-950 rounded-lg border border-slate-800 p-0.5 text-xs">
<button id="layoutLRBtn" onclick="setLayoutMode('LR')" title="Left-to-Right Hierarchical DAG" class="px-2.5 py-1 rounded bg-slate-800 text-cyan-400 font-mono font-medium transition">LR</button>
<button id="layoutUDBtn" onclick="setLayoutMode('UD')" title="Top-Down Hierarchical DAG" class="px-2.5 py-1 rounded text-slate-400 hover:text-slate-200 font-mono transition">UD</button>
<button id="layoutForceBtn" onclick="setLayoutMode('FORCE')" title="Force-Directed Physics Graph" class="px-2.5 py-1 rounded text-slate-400 hover:text-slate-200 font-mono transition">Force</button>
</div>
<!-- Load JSON File Input -->
<label class="cursor-pointer px-3 py-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-xs font-medium text-slate-200 flex items-center gap-1.5 transition">
<i data-lucide="upload" class="w-3.5 h-3.5 text-cyan-400"></i>
<span>Load JSON</span>
<input type="file" id="jsonFileInput" accept=".json" class="hidden" onchange="handleFileSelect(event)" />
</label>
<!-- Paste JSON Modal Trigger -->
<button onclick="openPasteModal()" class="px-3 py-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-xs font-medium text-slate-200 flex items-center gap-1.5 transition">
<i data-lucide="code-2" class="w-3.5 h-3.5 text-purple-400"></i>
<span class="hidden sm:inline">Paste / Edit</span>
</button>
<!-- Export JSON -->
<button onclick="exportFilteredJSON()" title="Export current DAG JSON" class="px-2.5 py-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-xs font-medium text-slate-200 flex items-center gap-1.5 transition">
<i data-lucide="download" class="w-3.5 h-3.5 text-emerald-400"></i>
<span class="hidden md:inline">Export</span>
</button>
<!-- Reset Demo Button -->
<button onclick="loadDemoDataset()" title="Reset to Built-in FMCW Radar Demo" class="p-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-slate-400 hover:text-white transition">
<i data-lucide="rotate-ccw" class="w-4 h-4"></i>
</button>
</div>
</header>
<!-- ================= SECONDARY FILTER & METRICS BAR ================= -->
<div class="bg-slate-900/70 border-b border-slate-800/80 px-4 py-2 flex flex-wrap items-center justify-between gap-4 text-xs z-10 shrink-0">
<!-- Left Filters -->
<div class="flex flex-wrap items-center gap-4">
<!-- Minimum Viability Score Slider -->
<div class="flex items-center gap-2.5 bg-slate-950/90 px-3 py-1.5 rounded-lg border border-slate-800">
<span class="text-slate-400 font-medium">Arbiter Gate (Min Score):</span>
<input type="range" id="minScoreSlider" min="1.0" max="9.5" step="0.25" value="1.0" oninput="applyFilters()" class="w-24 sm:w-32 cursor-pointer" />
<span id="minScoreValue" class="font-mono font-semibold text-cyan-400 w-8 text-right">1.0</span>
<label class="flex items-center gap-1.5 ml-2 pl-2 border-l border-slate-800 text-slate-400 cursor-pointer">
<input type="checkbox" id="hidePrunedCheckbox" onchange="applyFilters()" class="rounded bg-slate-900 border-slate-700 text-cyan-500 focus:ring-0" />
<span>Hide Below Gate</span>
</label>
</div>
<!-- Vector Filter -->
<div class="flex items-center gap-2">
<span class="text-slate-400 hidden sm:inline">Vector:</span>
<select id="vectorFilterSelect" onchange="applyFilters()" class="bg-slate-950 border border-slate-800 rounded-lg px-2.5 py-1.5 text-slate-200 font-medium focus:outline-none focus:border-cyan-500">
<option value="ALL">All 6 Adjacency Vectors</option>
<option value="Domain / Substrate Adjacency">1. Domain / Substrate</option>
<option value="Scale / Resolution Adjacency">2. Scale / Resolution</option>
<option value="Temporal / Workflow Adjacency">3. Temporal / Workflow</option>
<option value="Byproduct / Exhaust Adjacency">4. Byproduct / Exhaust</option>
<option value="Constraint / Environment Adjacency">5. Constraint / Environment</option>
<option value="Structural / Topological Inversion">6. Structural Inversion</option>
</select>
</div>
<!-- Mutated Pillar Filter -->
<div class="flex items-center gap-2">
<span class="text-slate-400 hidden sm:inline">Mutated Pillar:</span>
<select id="pillarFilterSelect" onchange="applyFilters()" class="bg-slate-950 border border-slate-800 rounded-lg px-2.5 py-1.5 text-slate-200 font-mono text-[11px] focus:outline-none focus:border-cyan-500">
<option value="ALL">All Pillars (4/4)</option>
<option value="input_signal">input_signal</option>
<option value="core_mechanism">core_mechanism</option>
<option value="governing_constraint">governing_constraint</option>
<option value="output_value">output_value</option>
</select>
</div>
</div>
<!-- Right Pipeline Telemetry Counters -->
<div class="flex items-center gap-3 font-mono text-[11px]">
<div class="px-2.5 py-1 rounded bg-slate-950 border border-slate-800 text-slate-300">
Nodes: <span id="statTotalNodes" class="text-white font-semibold">13</span>
</div>
<div class="px-2.5 py-1 rounded bg-slate-950 border border-slate-800 text-emerald-400">
Survivors (≥7.0): <span id="statHighViability" class="font-semibold">8</span>
</div>
<div id="orthogonalityBadge" class="px-2.5 py-1 rounded bg-emerald-950/60 border border-emerald-700/50 text-emerald-300 flex items-center gap-1">
<i data-lucide="shield-check" class="w-3.5 h-3.5"></i>
<span>Orthogonality Valid</span>
</div>
</div>
</div>
<!-- ================= MAIN WORKSPACE (CANVAS + INSPECTOR) ================= -->
<div class="flex-1 flex flex-col lg:flex-row overflow-hidden relative">
<!-- LEFT: VIS.JS GRAPH CANVAS AREA -->
<div id="canvasWrapper" class="flex-1 relative bg-tech-grid overflow-hidden flex flex-col">
<!-- Drag & Drop Overlay -->
<div id="dropOverlay" class="hidden absolute inset-0 bg-cyan-950/80 backdrop-blur-sm border-2 border-dashed border-cyan-400 z-30 flex flex-col items-center justify-center pointer-events-none">
<i data-lucide="file-json" class="w-16 h-16 text-cyan-300 mb-3 animate-bounce"></i>
<p class="text-lg font-bold text-white">Drop <code class="font-mono text-cyan-300">adjacency_idea_dag.json</code> to render</p>
<p class="text-xs text-cyan-200 mt-1">Supports Pydantic AdjacencyBranchingEngine schema</p>
</div>
<!-- Vis.js Container -->
<div id="visNetworkContainer" class="w-full flex-1"></div>
<!-- Floating Zoom / Fit Controls -->
<div class="absolute top-4 left-4 flex flex-col gap-1.5 z-10">
<button onclick="fitGraph()" title="Fit Graph to Screen" class="p-2 rounded-lg bg-slate-900/90 hover:bg-slate-800 text-slate-300 hover:text-white border border-slate-700/80 shadow-lg transition">
<i data-lucide="maximize-2" class="w-4 h-4"></i>
</button>
<button onclick="zoomGraph(1.25)" title="Zoom In" class="p-2 rounded-lg bg-slate-900/90 hover:bg-slate-800 text-slate-300 hover:text-white border border-slate-700/80 shadow-lg transition">
<i data-lucide="zoom-in" class="w-4 h-4"></i>
</button>
<button onclick="zoomGraph(0.8)" title="Zoom Out" class="p-2 rounded-lg bg-slate-900/90 hover:bg-slate-800 text-slate-300 hover:text-white border border-slate-700/80 shadow-lg transition">
<i data-lucide="zoom-out" class="w-4 h-4"></i>
</button>
</div>
<!-- Quick Lineage Breadcrumb Banner -->
<div id="lineageBreadcrumb" class="absolute top-4 right-4 max-w-md bg-slate-900/90 backdrop-blur-md border border-slate-800 rounded-lg px-3 py-1.5 text-xs font-mono text-slate-300 flex items-center gap-1.5 shadow-lg z-10">
<span class="text-slate-500">PATH:</span>
<span id="breadcrumbText" class="truncate text-cyan-300">root_0</span>
</div>
<!-- Bottom Dynamic Legend Bar -->
<div class="bg-slate-900/95 border-t border-slate-800 px-4 py-2 flex flex-wrap items-center justify-between gap-3 text-[11px] z-10">
<div id="legendContent" class="flex flex-wrap items-center gap-4">
<!-- Populated dynamically by updateLegend() -->
</div>
<div class="text-slate-400 font-mono hidden xl:flex items-center gap-3">
<span><strong class="text-slate-200">Click Node:</strong> Inspect 4 Pillars & Delta</span>
<span>•</span>
<span><strong class="text-slate-200">Scroll/Drag:</strong> Zoom & Pan</span>
</div>
</div>
</div>
<!-- RIGHT: DEEP NODE INSPECTOR SIDEBAR -->
<aside id="inspectorPanel" class="w-full lg:w-[460px] xl:w-[500px] h-[48vh] lg:h-full bg-slate-900 border-t lg:border-t-0 lg:border-l border-slate-800 flex flex-col overflow-hidden shrink-0 z-20">
<!-- Inspector Header -->
<div class="px-5 py-3.5 bg-slate-950/60 border-b border-slate-800 flex items-center justify-between shrink-0">
<div class="flex items-center gap-2">
<span id="inspHopBadge" class="px-2 py-0.5 rounded text-[11px] font-mono font-semibold bg-indigo-500/20 text-indigo-300 border border-indigo-500/40">
HOP 0 • ROOT
</span>
<span id="inspNodeId" class="font-mono text-xs text-slate-400">root_0</span>
</div>
<div id="inspScoreContainer" class="flex items-center gap-1.5">
<span class="text-[11px] text-slate-400 font-mono">VIABILITY:</span>
<span id="inspCompositeScore" class="px-2.5 py-0.5 rounded-md font-mono font-bold text-xs bg-emerald-500/20 text-emerald-300 border border-emerald-500/40">
ANCHOR
</span>
</div>
</div>
<!-- Scrollable Inspector Body -->
<div class="flex-1 overflow-y-auto p-5 space-y-5 select-text">
<!-- Node Title & Vector / Archetype Badges -->
<div>
<h2 id="inspTitle" class="text-lg font-bold text-white leading-snug">
24 GHz FMCW Radar Automotive Collision Avoidance
</h2>
<!-- Vector & Move Badges (Hidden for Root) -->
<div id="inspMetaBadges" class="hidden flex-wrap gap-2 mt-3">
<div class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md bg-slate-800 border border-slate-700 text-xs text-cyan-300">
<i data-lucide="compass" class="w-3.5 h-3.5"></i>
<span id="inspVectorBadge">Domain / Substrate Adjacency</span>
</div>
<div class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md bg-slate-800 border border-slate-700 text-xs text-purple-300">
<i data-lucide="sparkles" class="w-3.5 h-3.5"></i>
<span id="inspMoveBadge">Orthogonal Bridge</span>
</div>
</div>
</div>
<!-- Scenario or First-Principles Summary -->
<div class="bg-slate-950/80 border border-slate-800/90 rounded-xl p-3.5">
<div class="text-[11px] font-mono uppercase tracking-wider text-slate-400 mb-1.5 flex items-center gap-1.5">
<i data-lucide="cpu" class="w-3.5 h-3.5 text-cyan-400"></i>
<span id="inspSummaryHeader">First-Principles Deconstruction (Jargon Stripped)</span>
</div>
<p id="inspSummaryText" class="text-xs text-slate-300 leading-relaxed">
Continuous-wave electromagnetic chirp synthesis mixed with reflected echoes to extract beat frequencies proportional to target range and Doppler velocity.
</p>
</div>
<!-- PARENT-TO-CHILD SINGLE-HOP MUTATION DIFF (Hidden on Root) -->
<div id="inspMutationDiffBox" class="hidden bg-amber-950/20 border border-amber-500/30 rounded-xl p-4 space-y-3">
<div class="flex items-center justify-between">
<span class="text-[11px] font-mono font-semibold uppercase tracking-wider text-amber-300 flex items-center gap-1.5">
<i data-lucide="git-compare" class="w-4 h-4 text-amber-400"></i>
1-Degree-of-Freedom Mutation Delta
</span>
<span id="inspMutatedPillarTag" class="px-2 py-0.5 rounded bg-amber-500/20 text-amber-300 font-mono text-[11px] border border-amber-500/40">
output_value
</span>
</div>
<p id="inspMutationExplanation" class="text-xs text-amber-100/90 leading-relaxed">
Shifts the output value from high-speed vehicle braking actuation to micro-Doppler cardiopulmonary displacement tracking through dielectric barriers.
</p>
<!-- Before vs After Pillar Comparison -->
<div class="grid grid-cols-1 gap-2 pt-1 text-xs">
<div class="bg-slate-950/90 border border-slate-800 rounded-lg p-2.5">
<div class="text-[10px] font-mono text-slate-400 uppercase mb-0.5">
Parent (<span id="inspParentIdLabel">root_0</span>) Pillar State:
</div>
<div id="inspParentPillarText" class="text-slate-400 line-through decoration-rose-500/60">
Real-time time-to-collision (TTC) vector and automatic emergency braking (AEB) trigger.
</div>
</div>
<div class="bg-slate-950/90 border border-amber-500/40 rounded-lg p-2.5">
<div class="text-[10px] font-mono text-amber-400 uppercase mb-0.5">
New Mutated Pillar State:
</div>
<div id="inspChildPillarText" class="text-amber-200 font-medium">
Sub-millimeter chest wall displacement waveform (0.1–2.0 Hz) for non-contact respiration & apnea alerts.
</div>
</div>
</div>
</div>
<!-- THE 4 FUNCTIONAL PRIMITIVES ("LOCK 3, MUTATE 1" MATRIX) -->
<div>
<div class="flex items-center justify-between mb-2.5">
<h3 class="text-xs font-mono uppercase tracking-wider text-slate-400 flex items-center gap-1.5">
<i data-lucide="lock" class="w-3.5 h-3.5 text-cyan-400"></i>
<span>4 Functional Primitives (Lock 3, Mutate 1)</span>
</h3>
<span class="text-[10px] font-mono text-slate-500">Single-Hop Invariant</span>
</div>
<div id="inspPrimitivesList" class="space-y-2.5">
<!-- Dynamically populated cards for input_signal, core_mechanism, governing_constraint, output_value -->
</div>
</div>
<!-- FRICTION DELTA & PHYSICS VERIFICATION (Hidden on Root) -->
<div id="inspFrictionSection" class="hidden bg-slate-950/90 border border-slate-800 rounded-xl p-4 space-y-3.5">
<div class="flex items-center justify-between border-b border-slate-800 pb-2.5">
<div>
<h3 class="text-xs font-mono uppercase tracking-wider text-slate-300 font-semibold">
Friction Delta Rubric
</h3>
<p class="text-[11px] text-slate-500 font-mono">
0.35 × Pain + 0.40 × Feasibility + 0.25 × Barrier Reduction
</p>
</div>
<div id="inspRubricTotal" class="text-lg font-mono font-bold text-emerald-400">
8.25 / 10
</div>
</div>
<!-- 3 Score Bars -->
<div class="space-y-2.5 text-xs">
<div>
<div class="flex justify-between mb-1">
<span class="text-slate-300">Pain Severity in Target Niche <span class="text-slate-500 font-mono">(35%)</span></span>
<span id="scorePainText" class="font-mono font-semibold text-cyan-300">9 / 10</span>
</div>
<div class="w-full h-2 bg-slate-800 rounded-full overflow-hidden">
<div id="scorePainBar" class="h-full bg-cyan-500 rounded-full transition-all duration-300" style="width: 90%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span class="text-slate-300">Direct Technical Transferability <span class="text-slate-500 font-mono">(40%)</span></span>
<span id="scoreFeasText" class="font-mono font-semibold text-emerald-300">8 / 10</span>
</div>
<div class="w-full h-2 bg-slate-800 rounded-full overflow-hidden">
<div id="scoreFeasBar" class="h-full bg-emerald-500 rounded-full transition-all duration-300" style="width: 80%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span class="text-slate-300">Regulatory / Adoption Barrier Reduction <span class="text-slate-500 font-mono">(25%)</span></span>
<span id="scoreBarrierText" class="font-mono font-semibold text-purple-300">8 / 10</span>
</div>
<div class="w-full h-2 bg-slate-800 rounded-full overflow-hidden">
<div id="scoreBarrierBar" class="h-full bg-purple-500 rounded-full transition-all duration-300" style="width: 80%"></div>
</div>
</div>
</div>
<!-- Physics / Scaling Law Check -->
<div class="pt-2 border-t border-slate-800/80">
<div class="text-[10px] font-mono uppercase text-emerald-400 mb-1 flex items-center gap-1">
<i data-lucide="check-circle-2" class="w-3.5 h-3.5"></i>
<span>Physics & Scaling Law Verification Check</span>
</div>
<p id="inspPhysicsCheck" class="text-xs text-slate-300 font-mono bg-slate-900/90 p-2.5 rounded-lg border border-slate-800 leading-relaxed">
Verified: At 24 GHz (wavelength ~12.5 mm), a 0.5 mm chest wall displacement produces a 28.8-degree phase shift—well above thermal phase noise floor at <5m indoor range.
</p>
</div>
</div>
<!-- Immediate Children / Downstream Branches Quick Jump -->
<div id="inspChildrenSection" class="pt-2">
<div class="text-[11px] font-mono uppercase tracking-wider text-slate-400 mb-2">
Downstream Adjacency Branches (<span id="inspChildrenCount">6</span>)
</div>
<div id="inspChildrenList" class="grid grid-cols-1 gap-1.5">
<!-- Dynamically populated buttons to jump to child nodes -->
</div>
</div>
</div>
</aside>
</div>
<!-- ================= PASTE / EDIT JSON MODAL ================= -->
<div id="pasteModal" class="hidden fixed inset-0 bg-slate-950/80 backdrop-blur-sm z-50 flex items-center justify-center p-4">
<div class="bg-slate-900 border border-slate-700 rounded-2xl max-w-3xl w-full flex flex-col max-h-[85vh] shadow-2xl overflow-hidden">
<div class="px-5 py-3.5 bg-slate-950 border-b border-slate-800 flex items-center justify-between">
<div class="flex items-center gap-2">
<i data-lucide="file-json" class="w-5 h-5 text-cyan-400"></i>
<h3 class="font-bold text-sm text-white">Load or Edit <code class="font-mono text-cyan-300">adjacency_idea_dag.json</code></h3>
</div>
<button onclick="closePasteModal()" class="text-slate-400 hover:text-white">
<i data-lucide="x" class="w-5 h-5"></i>
</button>
</div>
<div class="p-5 flex-1 flex flex-col gap-3 overflow-hidden">
<p class="text-xs text-slate-400">
Paste the JSON output generated by <code class="font-mono text-slate-200">AdjacencyBranchingEngine.export_dag_json()</code> below. The viewer automatically validates <code class="font-mono text-slate-200">composite_score</code> and checks 2-hop orthogonality constraints.
</p>
<div id="jsonErrorBanner" class="hidden px-3 py-2 rounded-lg bg-rose-950/90 border border-rose-500/50 text-rose-200 text-xs font-mono"></div>
<textarea id="jsonPasteTextarea" spellcheck="false" class="w-full flex-1 bg-slate-950 border border-slate-800 rounded-xl p-3.5 font-mono text-xs text-slate-200 focus:outline-none focus:border-cyan-500 resize-none"></textarea>
</div>
<div class="px-5 py-3 bg-slate-950 border-t border-slate-800 flex items-center justify-between">
<button onclick="formatModalJSON()" class="px-3 py-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 text-xs font-mono text-slate-300 transition">
Prettify JSON
</button>
<div class="flex items-center gap-2">
<button onclick="closePasteModal()" class="px-4 py-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 text-xs font-medium text-slate-300 transition">
Cancel
</button>
<button onclick="applyPastedJSON()" class="px-4 py-1.5 rounded-lg bg-cyan-600 hover:bg-cyan-500 text-xs font-semibold text-white shadow transition">
Render DAG Graph
</button>
</div>
</div>
</div>
</div>
<!-- ================= TOAST NOTIFICATION ================= -->
<div id="toastBanner" class="fixed bottom-14 left-1/2 -translate-x-1/2 px-4 py-2 rounded-xl bg-slate-900/95 border border-cyan-500/40 text-xs font-mono text-cyan-200 shadow-2xl z-50 transition-all duration-300 opacity-0 pointer-events-none flex items-center gap-2">
<i data-lucide="info" class="w-4 h-4 text-cyan-400"></i>
<span id="toastMessage">Loaded DAG</span>
</div>
<!-- ================= APPLICATION JAVASCRIPT ================= -->
<script>
/********************************************************************
* 1. BUILT-IN REALISTIC DEMO DATASET (adjacency_idea_dag.json)
* Root: 24 GHz FMCW Radar -> 6 Hop-1 Spin-offs -> 6 Hop-2 Spin-offs
********************************************************************/
const DEMO_DAG_DATA = {
"nodes": {
"root_0": {
"node_id": "root_0",
"title": "24 GHz Automotive FMCW Collision Radar",
"domain_jargon_stripped_summary": "Synthesizes linear frequency-modulated continuous-wave (FMCW) millimeter-wave sweeps, mixes reflected echoes with the local oscillator to extract intermediate beat frequencies, and computes range/velocity matrices via 2D Fast Fourier Transform (Range-Doppler FFT).",
"primitives": {
"input_signal": "24 GHz linear frequency-modulated electromagnetic chirp reflecting off metallic/dielectric obstacles in outdoor line-of-sight.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat frequency & phase extraction.",
"governing_constraint": "Automotive bumper thermal envelope (-40C to 105C), multipath clutter from asphalt, and strict <50ms AEB latency.",
"output_value": "Real-time obstacle range/velocity vector to trigger Automatic Emergency Braking (AEB)."
}
},
/* ==================== 6 HOP-1 SPIN-OFF NODES ==================== */
"hop1_v1": {
"node_id": "hop1_v1",
"parent_id": "root_0",
"hop_depth": 1,
"applied_vector": "Domain / Substrate Adjacency",
"archetypal_move": "Orthogonal Bridge (2-Node Recombination)",
"mutated_pillar": "input_signal",
"locked_pillars": ["core_mechanism", "governing_constraint", "output_value"],
"mutation_delta_explanation": "Swaps the propagation medium from open-air highway line-of-sight to through-drywall indoor residential rooms, capturing sub-millimeter human chest wall micro-Doppler reflections.",
"title": "Through-Wall Non-Contact Cardiopulmonary Apnea & Fall Radar",
"updated_primitives": {
"input_signal": "24 GHz RF chirp penetrating gypsum drywall/bedding and reflecting off sub-millimeter human thoracic skin movement.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat frequency & phase unwrap extraction.",
"governing_constraint": "Indoor FCC Part 15 EIRP limits, clutter rejection from ceiling fans, and <50ms fall trajectory latency.",
"output_value": "Continuous respiratory rate, heart-rate variability, and real-time elder fall alert vector without cameras."
},
"concrete_application_scenario": "Ceiling-mounted behind-drywall sensor in memory-care facilities and NICUs that monitors sleep apnea and bed-exit falls with zero optical privacy intrusion.",
"friction_delta": {
"pain_severity_score": 9,
"technical_feasibility_score": 9,
"regulatory_or_adoption_barrier_reduction": 8,
"physics_or_logic_violation_check": "PASS: At 24 GHz (lambda=12.5mm), a 0.5mm chest displacement yields a 28.8 deg phase shift, easily resolved via arctangent demodulation."
},
"composite_score": 8.75
},
"hop1_v2": {
"node_id": "hop1_v2",
"parent_id": "root_0",
"hop_depth": 1,
"applied_vector": "Scale / Resolution Adjacency",
"archetypal_move": "Orthogonal Bridge (2-Node Recombination)",
"mutated_pillar": "governing_constraint",
"locked_pillars": ["input_signal", "core_mechanism", "output_value"],
"mutation_delta_explanation": "Compresses spatial operating range by 3 orders of magnitude (from 150m highway down to 50mm near-field waveguide) to resolve sub-millimeter internal dielectric voids inside solid composite slabs.",
"title": "Near-Field Millimeter-Wave Sub-Surface Delamination Scanner",
"updated_primitives": {
"input_signal": "Swept millimeter-wave chirp coupled into carbon/glass-fiber composite laminates or cured concrete.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler/Phase FFT depth profiling.",
"governing_constraint": "Near-field standoff distance (<20mm) and dielectric attenuation depth limit (~4cm in GFRP) rather than highway multipath.",
"output_value": "3D internal void, moisture ingress, and delamination defect map for non-destructive testing (NDT)."
},
"concrete_application_scenario": "Handheld or robotic gantry scanner inspecting wind turbine blades and aerospace radomes for micro-delamination without ultrasound couplant gels.",
"friction_delta": {
"pain_severity_score": 8,
"technical_feasibility_score": 8,
"regulatory_or_adoption_barrier_reduction": 9,
"physics_or_logic_violation_check": "PASS: Non-conductive GFRP/epoxy is transparent at 24-60 GHz; refractive index contrast at air voids produces strong reflection spikes."
},
"composite_score": 8.25
},
"hop1_v3": {
"node_id": "hop1_v3",
"parent_id": "root_0",
"hop_depth": 1,
"applied_vector": "Temporal / Workflow Adjacency",
"archetypal_move": "Pickaxe Extraction (Internal Scaffolding)",
"mutated_pillar": "output_value",
"locked_pillars": ["input_signal", "core_mechanism", "governing_constraint"],
"mutation_delta_explanation": "Shifts upstream in the radar manufacturing workflow: extracts the internal end-of-line Doppler target simulator rig used to calibrate automotive radars and packages it as a standalone field certification appliance.",
"title": "Portable Electronic Radar Target Simulator (RTS) Calibration Box",
"updated_primitives": {
"input_signal": "24/77 GHz chirp emitted by a vehicle bumper radar under post-collision repair.",
"core_mechanism": "Homodyne downconversion + digital delay line / Doppler frequency shifter re-transmitting synthetic ghost echoes.",
"governing_constraint": "Automotive body-shop floor space (<1.5mbay) and <1ns phase-coherent digital repeater delay.",
"output_value": "Certified ADAS calibration pass/fail cryptographic receipt for insurance compliance after bumper replacement."
},
"concrete_application_scenario": "Compact tripod-mounted box for independent auto body shops to recalibrate ADAS radars in a 3-meter bay instead of needing a 30-meter corner-reflector hall.",
"friction_delta": {
"pain_severity_score": 9,
"technical_feasibility_score": 8,
"regulatory_or_adoption_barrier_reduction": 7,
"physics_or_logic_violation_check": "PASS: Digital RF memory (DRFM) andswitched fiber/coax delay lines accurately synthesize virtual targets from 2m to 150m."
},
"composite_score": 8.10
},
"hop1_v4": {
"node_id": "hop1_v4",
"parent_id": "root_0",
"hop_depth": 1,
"applied_vector": "Byproduct / Exhaust Adjacency",
"archetypal_move": "Symbiotic Parasite (Host Attachment)",
"mutated_pillar": "output_value",
"locked_pillars": ["input_signal", "core_mechanism", "governing_constraint"],
"mutation_delta_explanation": "Repurposes the rejected 'ground-clutter and rain backscatter noise floor' (normally filtered out and discarded by AEB algorithms) into a high-precision road surface friction and black-ice classifier.",
"title": "Backscatter Clutter Road-Surface Black-Ice & Hydroplane Classifier",
"updated_primitives": {
"input_signal": "24 GHz grazing-angle radar chirp reflecting off the asphalt immediately ahead of the bumper.",
"core_mechanism": "Homodyne quadrature mixing + Range-Doppler FFT analyzing polarization & spectral kurtosis of discarded ground clutter.",
"governing_constraint": "Automotive bumper thermal envelope (-40C to 105C) and <50ms real-time traction controller telemetry.",
"output_value": "Continuous road friction coefficient (dry asphalt, water film depth, black ice) fed to ABS/torque-vectoring ECU."
},
"concrete_application_scenario": "Zero-hardware firmware upgrade for existing fleet trucks and EVs that turns discarded radar ground-clutter into a localized black-ice warning network.",
"friction_delta": {
"pain_severity_score": 7,
"technical_feasibility_score": 8,
"regulatory_or_adoption_barrier_reduction": 8,
"physics_or_logic_violation_check": "PASS: Liquid water and crystalline ice exhibit distinct complex permittivity (epsilon') at 24 GHz, altering Bragg backscatter amplitude."
},
"composite_score": 7.65
},
"hop1_v5": {
"node_id": "hop1_v5",
"parent_id": "root_0",
"hop_depth": 1,
"applied_vector": "Constraint / Environment Adjacency",
"archetypal_move": "Passive / Active Energy Flip",
"mutated_pillar": "core_mechanism",
"locked_pillars": ["input_signal", "governing_constraint", "output_value"],
"mutation_delta_explanation": "Eliminates active onboard RF chirp generation to survive zero-power constraints; converts the transceiver into a passive Chipless Surface Acoustic Wave (SAW) harmonic reflector interrogated externally.",
"title": "Zero-Power Passive Harmonic Tag for Underground Mining & Silo Assets",
"updated_primitives": {
"input_signal": "24 GHz electromagnetic sweep illuminating dust-obscured subterranean tunnels.",
"core_mechanism": "Passive piezoelectric SAW delay-line modulation reflecting a phase-coded echo with zero battery or active LO.",
"governing_constraint": "ATEX explosive methane/coal-dust intrinsic safety (zero electrical spark energy) and extreme vibration.",
"output_value": "Real-time obstacle range/velocity vector for automated haul trucks in GPS-denied mines."
},
"concrete_application_scenario": "Intrinsically safe, battery-free collision avoidance tags bolted to underground mine personnel vests and ventilation bulkheads.",
"friction_delta": {
"pain_severity_score": 7,
"technical_feasibility_score": 6,
"regulatory_or_adoption_barrier_reduction": 6,
"physics_or_logic_violation_check": "PASS with caution: Passive radar cross-section drops as 1/R^4; practical range limited to <25 meters without retrodirective Van Atta arrays."
},
"composite_score": 6.35
},
"hop1_v6": {
"node_id": "hop1_v6",
"parent_id": "root_0",
"hop_depth": 1,
"applied_vector": "Structural / Topological Inversion",
"archetypal_move": "Symbiotic Parasite (Host Attachment)",
"mutated_pillar": "governing_constraint",
"locked_pillars": ["input_signal", "core_mechanism", "output_value"],
"mutation_delta_explanation": "Inverts the topology: instead of mounting a moving radar on an expensive vehicle looking at stationary objects, mounts stationary ultra-cheap radars inside gravity-fed grain/ore chutes while bulk material falls past.",
"title": "Gravity-Chute Bulk Solids Mass-Flow & Foreign Metal Velocimeter",
"updated_primitives": {
"input_signal": "24 GHz FMCW chirp illuminating a dense curtain of falling grain, cement clinker, or crushed ore.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT velocity distribution integration.",
"governing_constraint": "Abrasive opaque dust clouds and acoustic vibration inside enclosed steel transfer chutes (where optical lasers blind in 10 seconds).",
"output_value": "Real-time mass flow rate (tons/hr) and pneumatic diverter trigger upon chute-plugging velocity stall."
},
"concrete_application_scenario": "Bolted to the outside of a HDPE viewing window on agricultural grain elevators and mining crushers to prevent catastrophic chute blockages.",
"friction_delta": {
"pain_severity_score": 8,
"technical_feasibility_score": 9,
"regulatory_or_adoption_barrier_reduction": 9,
"physics_or_logic_violation_check": "PASS: 24 GHz easily penetrates high-density airborne silica/grain dust (Mie scattering negligible when particle diameter << 12.5mm)."
},
"composite_score": 8.65
},
/* ==================== 6 HOP-2 FRONTIER SPIN-OFFS ==================== */
/* Expanded from Top Survivor 1: hop1_v1 (Through-Wall Cardiopulmonary Radar) */
"hop1_v1_hop2_1": {
"node_id": "hop1_v1_hop2_1",
"parent_id": "hop1_v1",
"hop_depth": 2,
"applied_vector": "Byproduct / Exhaust Adjacency",
"archetypal_move": "Symbiotic Parasite (Host Attachment)",
"mutated_pillar": "output_value",
"locked_pillars": ["input_signal", "core_mechanism", "governing_constraint"],
"mutation_delta_explanation": "Locks the indoor through-wall 24 GHz bio-radar setup from Hop 1, but mutates the output_value to harvest the multi-person respiratory occupancy signature for closed-loop HVAC CO2/ventilation damper control.",
"title": "Metabolic-Load HVAC Damper Controller via Micro-Doppler Respiration",
"updated_primitives": {
"input_signal": "24 GHz RF chirp penetrating gypsum drywall and reflecting off human thoracic movements in conference rooms.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat frequency & phase unwrap extraction.",
"governing_constraint": "Indoor FCC Part 15 EIRP limits, ceiling fan clutter rejection, and BACnet building bus integration.",
"output_value": "Exact static occupant headcount + aggregate metabolic breathing rate to modulate variable-air-volume (VAV) dampers before CO2 rises."
},
"concrete_application_scenario": "Replaces sluggish wall CO2 sensors (which lag occupancy by 20 minutes) and PIR motion sensors (which turn off lights when people sit still typing).",
"friction_delta": {
"pain_severity_score": 8,
"technical_feasibility_score": 9,
"regulatory_or_adoption_barrier_reduction": 10,
"physics_or_logic_violation_check": "PASS: Eliminates FDA medical device classification entirely while using 100% identical hardware to hop1_v1."
},
"composite_score": 8.90
},
"hop1_v1_hop2_2": {
"node_id": "hop1_v1_hop2_2",
"parent_id": "hop1_v1",
"hop_depth": 2,
"applied_vector": "Constraint / Environment Adjacency",
"archetypal_move": "Orthogonal Bridge (2-Node Recombination)",
"mutated_pillar": "governing_constraint",
"locked_pillars": ["input_signal", "core_mechanism", "output_value"],
"mutation_delta_explanation": "Locks the non-contact cardiopulmonary input_signal, core_mechanism, and output_value from Hop 1, but shifts the governing_constraint to high-field 3-Tesla MRI bores where metallic ECG leads cause RF burns.",
"title": "MRI-Bore Waveguide-Coupled Non-Contact Cardiac Gating Radar",
"updated_primitives": {
"input_signal": "24 GHz RF chirp guided down a dielectric plastic tube onto a patient's chest inside an MRI bore.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat frequency & phase unwrap extraction.",
"governing_constraint": "Zero ferromagnetic components inside the 3-Tesla Faraday cage and immunity to kHz gradient coil switching pulses.",
"output_value": "Sub-millisecond R-wave mechanical apex-beat trigger to gate MRI slice acquisition without adhesive ECG electrodes."
},
"concrete_application_scenario": "Cuts patient prep time by 6 minutes per cardiac MRI scan by eliminating chest shaving and MRI-safe fiber-optic ECG lead placement.",
"friction_delta": {
"pain_severity_score": 9,
"technical_feasibility_score": 8,
"regulatory_or_adoption_barrier_reduction": 6,
"physics_or_logic_violation_check": "PASS: 24 GHz is far above the 128 MHz Larmor frequency of a 3T MRI; hollow PTFE dielectric waveguide keeps electronics outside the bore."
},
"composite_score": 7.85
},
"hop1_v1_hop2_3": {
"node_id": "hop1_v1_hop2_3",
"parent_id": "hop1_v1",
"hop_depth": 2,
"applied_vector": "Temporal / Workflow Adjacency",
"archetypal_move": "Pickaxe Extraction (Internal Scaffolding)",
"mutated_pillar": "core_mechanism",
"locked_pillars": ["input_signal", "governing_constraint", "output_value"],
"mutation_delta_explanation": "Locks the indoor non-contact bio-sensing domain, but swaps the active 24 GHz transceiver mechanism for opportunistic Channel State Information (CSI) phase harvesting from existing commodity Wi-Fi 6E/7 routers.",
"title": "Zero-Hardware Wi-Fi 6E CSI Phase Apnea & Intrusion Daemon",
"updated_primitives": {
"input_signal": "Ambient 6 GHz / 24 GHz indoor radio subcarriers reflecting off human thoracic motion.",
"core_mechanism": "OFDM subcarrier Channel State Information (CSI) complex phase-ratio quotient denoising across MIMO antennas.",
"governing_constraint": "Indoor FCC Part 15 limits, unsynchronized commercial router clock drift, and ceiling fan clutter.",
"output_value": "Continuous respiratory rate and elder fall alert vector using existing home mesh routers."
},
"concrete_application_scenario": "Downloadable ISP router firmware module for aging-in-place telemetry requiring zero dedicated sensor installation.",
"friction_delta": {
"pain_severity_score": 8,
"technical_feasibility_score": 6,
"regulatory_or_adoption_barrier_reduction": 9,
"physics_or_logic_violation_check": "PASS with SNR tradeoff: 6 GHz wavelength (5cm) has 4x lower phase sensitivity than 24 GHz, requiring MIMO antenna ratio cancellation."
},
"composite_score": 7.45
},
/* Expanded from Top Survivor 2: hop1_v6 (Gravity-Chute Bulk Solids Velocimeter) */
"hop1_v6_hop2_1": {
"node_id": "hop1_v6_hop2_1",
"parent_id": "hop1_v6",
"hop_depth": 2,
"applied_vector": "Domain / Substrate Adjacency",
"archetypal_move": "Orthogonal Bridge (2-Node Recombination)",
"mutated_pillar": "input_signal",
"locked_pillars": ["core_mechanism", "governing_constraint", "output_value"],
"mutation_delta_explanation": "Locks the stationary chute-mounted topology and harsh dust constraint from hop1_v6, but mutates the input_signal from falling dry grain/ore to pneumatic pulverized coal & biomass injection pipes in steel blast furnaces.",
"title": "Pneumatic Pulverized-Fuel Stoichiometric Mass-Flow Balance Sensor",
"updated_primitives": {
"input_signal": "24 GHz FMCW chirp coupled through a ceramic window into high-velocity gas-entrained pulverized coal/biomass pipes.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT velocity & cross-sectional density integration.",
"governing_constraint": "Abrasive opaque dust clouds, 400C pipe wall temperatures, and acoustic vibration.",
"output_value": "Real-time per-nozzle mass flow rate (tons/hr) to balance oxygen-to-fuel stoichiometry across 24 furnace tuyeres."
},
"concrete_application_scenario": "Prevents nozzle plugging and reduces coke consumption in steel blast furnaces and rotary cement kilns.",
"friction_delta": {
"pain_severity_score": 9,
"technical_feasibility_score": 8,
"regulatory_or_adoption_barrier_reduction": 8,
"physics_or_logic_violation_check": "PASS: Sintered alumina ceramic window withstands 1200C and abrasion while remaining transparent to 24 GHz RF."
},
"composite_score": 8.35
},
"hop1_v6_hop2_2": {
"node_id": "hop1_v6_hop2_2",
"parent_id": "hop1_v6",
"hop_depth": 2,
"applied_vector": "Byproduct / Exhaust Adjacency",
"archetypal_move": "Passive / Active Energy Flip",
"mutated_pillar": "output_value",
"locked_pillars": ["input_signal", "core_mechanism", "governing_constraint"],
"mutation_delta_explanation": "Locks the gravity-chute radar hardware from hop1_v6, but extracts the dielectric phase attenuation byproduct of the falling grain curtain to compute real-time grain moisture percentage alongside velocity.",
"title": "Dual-Parameter Chute Velocimeter & Inline Dielectric Moisture Analyzer",
"updated_primitives": {
"input_signal": "24 GHz FMCW chirp illuminating a dense curtain of falling grain inside a transfer chute.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT extracting both Doppler velocity and bulk phase retardation.",
"governing_constraint": "Abrasive opaque dust clouds and vibration inside enclosed steel agricultural chutes.",
"output_value": "Simultaneous dry-matter mass flow (tons/hr) + real-time % moisture content to auto-throttle grain dryer burners."
},
"concrete_application_scenario": "Allows commercial grain dryers to modulate natural gas burners in real time without capacitive plates that gum up with wet corn husks.",
"friction_delta": {
"pain_severity_score": 9,
"technical_feasibility_score": 9,
"regulatory_or_adoption_barrier_reduction": 9,
"physics_or_logic_violation_check": "PASS: Free water has epsilon_r ~ 80 vs dry grain epsilon_r ~ 3; phase delay normalized by Doppler density yields moisture %."
},
"composite_score": 9.00
},
"hop1_v6_hop2_3": {
"node_id": "hop1_v6_hop2_3",
"parent_id": "hop1_v6",
"hop_depth": 2,
"applied_vector": "Scale / Resolution Adjacency",
"archetypal_move": "Orthogonal Bridge (2-Node Recombination)",
"mutated_pillar": "core_mechanism",
"locked_pillars": ["input_signal", "governing_constraint", "output_value"],
"mutation_delta_explanation": "Locks the gravity-fed chute topology and mass-flow output_value, but scales up to 120 GHz sub-THz wideband chirp mixing to resolve individual pharmaceutical tablet fractures and missing blister pellets in free-fall.",
"title": "120 GHz Free-Fall Pharmaceutical Tablet Integrity & Count Gate",
"updated_primitives": {
"input_signal": "Millimeter-wave chirp illuminating high-speed falling capsules/tablets in opaque dust-laden packaging chutes.",
"core_mechanism": "120 GHz wideband SiGe BiCMOS homodyne mixing resolving 1.2mm micro-Doppler & RCS mass signatures per tablet.",
"governing_constraint": "Opaque talcum/excipient dust clouds where optical cameras require frequent line stoppages for lens wiping.",
"output_value": "100% inline tablet count, broken-pill pneumatic rejection trigger, and mass verification at 2,000 tablets/ minute."
},
"concrete_application_scenario": "High-speed nutraceutical and pharmaceutical bottling lines plagued by powder dust false-rejects on optical sensors.",
"friction_delta": {
"pain_severity_score": 7,
"technical_feasibility_score": 7,
"regulatory_or_adoption_barrier_reduction": 6,
"physics_or_logic_violation_check": "PASS: 120 GHz (lambda=2.5mm) provides sufficient Rayleigh/Mie RCS sensitivity to distinguish a chipped 6mm tablet from an intact one."
},
"composite_score": 6.75
}
},
"edges": [
{ "source": "root_0", "target": "hop1_v1", "vector": "Domain / Substrate Adjacency", "mutated_pillar": "input_signal" },
{ "source": "root_0", "target": "hop1_v2", "vector": "Scale / Resolution Adjacency", "mutated_pillar": "governing_constraint" },
{ "source": "root_0", "target": "hop1_v3", "vector": "Temporal / Workflow Adjacency", "mutated_pillar": "output_value" },
{ "source": "root_0", "target": "hop1_v4", "vector": "Byproduct / Exhaust Adjacency", "mutated_pillar": "output_value" },
{ "source": "root_0", "target": "hop1_v5", "vector": "Constraint / Environment Adjacency", "mutated_pillar": "core_mechanism" },
{ "source": "root_0", "target": "hop1_v6", "vector": "Structural / Topological Inversion", "mutated_pillar": "governing_constraint" },
{ "source": "hop1_v1", "target": "hop1_v1_hop2_1", "vector": "Byproduct / Exhaust Adjacency", "mutated_pillar": "output_value" },
{ "source": "hop1_v1", "target": "hop1_v1_hop2_2", "vector": "Constraint / Environment Adjacency", "mutated_pillar": "governing_constraint" },
{ "source": "hop1_v1", "target": "hop1_v1_hop2_3", "vector": "Temporal / Workflow Adjacency", "mutated_pillar": "core_mechanism" },
{ "source": "hop1_v6", "target": "hop1_v6_hop2_1", "vector": "Domain / Substrate Adjacency", "mutated_pillar": "input_signal" },
{ "source": "hop1_v6", "target": "hop1_v6_hop2_2", "vector": "Byproduct / Exhaust Adjacency", "mutated_pillar": "output_value" },
{ "source": "hop1_v6", "target": "hop1_v6_hop2_3", "vector": "Scale / Resolution Adjacency", "mutated_pillar": "core_mechanism" }
]
};
/********************************************************************
* 2. COLOR PALETTES & VECTOR DEFINITIONS
********************************************************************/
const VECTOR_PALETTE = {
"Domain / Substrate Adjacency": { bg: "#0284c7", border: "#38bdf8", text: "#e0f2fe", short: "Domain/Substrate" },
"Scale / Resolution Adjacency": { bg: "#7c3aed", border: "#a78bfa", text: "#ede9fe", short: "Scale/Resolution" },
"Temporal / Workflow Adjacency": { bg: "#d97706", border: "#fbbf24", text: "#fef3c7", short: "Temporal/Workflow" },
"Byproduct / Exhaust Adjacency": { bg: "#059669", border: "#34d399", text: "#d1fae5", short: "Byproduct/Exhaust" },
"Constraint / Environment Adjacency":{ bg: "#e11d48", border: "#fb7185", text: "#ffe4e6", short: "Constraint/Env" },
"Structural / Topological Inversion":{ bg: "#4f46e5", border: "#818cf8", text: "#e0e7ff", short: "Structural Flip" }
};
const PILLAR_LABELS = {
"input_signal": "Input Signal / Material",
"core_mechanism": "Core Mechanism / Law",
"governing_constraint": "Governing Constraint",
"output_value": "Output Value / Action"
};
// Global Application State
let rawDagData = null;
let visNetwork = null;
let visNodesDataSet = new vis.DataSet();
let visEdgesDataSet = new vis.DataSet();
let currentColorMode = 'viability'; // 'viability' | 'hop' | 'vector'
let currentLayoutMode = 'LR'; // 'LR' | 'UD' | 'FORCE'
let selectedNodeId = 'root_0';
/********************************************************************
* 3. INITIALIZATION & NETWORK SETUP
********************************************************************/
window.addEventListener('DOMContentLoaded', () => {
lucide.createIcons();
setupDragAndDrop();
loadDemoDataset();
});
function loadDemoDataset() {
// Deep clone demo data
rawDagData = JSON.parse(JSON.stringify(DEMO_DAG_DATA));
normalizeAndValidateDAG(rawDagData);
document.getElementById('datasetTitleDisplay').textContent =
`Loaded: ${rawDagData.nodes['root_0']?.title || 'Adjacency DAG'} (${Object.keys(rawDagData.nodes).length} Nodes)`;
renderVisGraph();
selectNode('root_0');
showToast("Loaded built-in 24 GHz FMCW Radar Adjacency DAG (13 nodes)");
}
/**
* Ensures every node has a computed composite_score and checks Hop-2 orthogonality
*/
function normalizeAndValidateDAG(dag) {
let orthoViolations = 0;
Object.values(dag.nodes).forEach(node => {
const isRoot = !node.hop_depth || node.hop_depth === 0 || node.node_id === 'root_0';
if (isRoot) {
node.hop_depth = 0;
} else {
// Compute composite_score if missing
if (typeof node.composite_score !== 'number' && node.friction_delta) {
const fd = node.friction_delta;
node.composite_score = Number(
((fd.pain_severity_score * 0.35) +
(fd.technical_feasibility_score * 0.40) +
(fd.regulatory_or_adoption_barrier_reduction * 0.25)).toFixed(2)
);
}
// Check 2-Hop Orthogonality against Parent
if (node.hop_depth === 2 && node.parent_id && dag.nodes[node.parent_id]) {
const parent = dag.nodes[node.parent_id];
if (parent.applied_vector === node.applied_vector || parent.mutated_pillar === node.mutated_pillar) {
orthoViolations++;
node._orthoWarning = true;
}
}
}
});
// Update Orthogonality Badge in Header
const badge = document.getElementById('orthogonalityBadge');
if (orthoViolations === 0) {
badge.className = "px-2.5 py-1 rounded bg-emerald-950/60 border border-emerald-700/50 text-emerald-300 flex items-center gap-1";
badge.innerHTML = `<i data-lucide="shield-check" class="w-3.5 h-3.5"></i><span>Orthogonality Valid</span>`;
} else {
badge.className = "px-2.5 py-1 rounded bg-rose-950/70 border border-rose-600/50 text-rose-300 flex items-center gap-1";
badge.innerHTML = `<i data-lucide="alert-triangle" class="w-3.5 h-3.5"></i><span>${orthoViolations} Ortho Collision(s)</span>`;
}
lucide.createIcons();
}
/********************************************************************
* 4. NODE & EDGE STYLING ENGINE (3 COLOR MODES)
********************************************************************/
function getNodeColors(node, isDimmed) {
if (isDimmed) {
return {
background: '#1e293b',
border: '#334155',
fontColor: '#64748b',
highlightBg: '#334155',
highlightBorder: '#475569'
};
}
// Root Node Styling
if (node.hop_depth === 0) {
return {
background: '#312e81', // Indigo 900
border: '#818cf8', // Indigo 400
fontColor: '#ffffff',
highlightBg: '#3730a3',
highlightBorder: '#a5b4fc'
};
}
const score = node.composite_score || 0;
if (currentColorMode === 'viability') {
if (score >= 8.2) {
// Elite Viability (Cyan/Emerald)
return {
background: '#064e3b',
border: '#10b981',
fontColor: '#ecfdf5',
highlightBg: '#047857',
highlightBorder: '#34d399'
};
} else if (score >= 7.0) {
// Strong Viability (Teal/Sky)
return {
background: '#0c4a6e',
border: '#38bdf8',
fontColor: '#f0f9ff',
highlightBg: '#0369a1',
highlightBorder: '#7dd3fc'
};
} else if (score >= 5.5) {
// Moderate Friction (Amber)
return {
background: '#78350f',
border: '#f59e0b',
fontColor: '#fffbeb',
highlightBg: '#92400e',
highlightBorder: '#fbbf24'
};
} else {
// High Friction / Pruned (Crimson)
return {
background: '#7f1d1d',
border: '#ef4444',
fontColor: '#fef2f2',
highlightBg: '#991b1b',
highlightBorder: '#f87171'
};
}
}
if (currentColorMode === 'hop') {
if (node.hop_depth === 1) {
return {
background: '#0f2942',
border: '#0ea5e9',
fontColor: '#e0f2fe',
highlightBg: '#0369a1',
highlightBorder: '#38bdf8'
};
} else {
return {
background: '#063e31',
border: '#10b981',
fontColor: '#d1fae5',
highlightBg: '#047857',
highlightBorder: '#34d399'
};
}
}
if (currentColorMode === 'vector') {
const pal = VECTOR_PALETTE[node.applied_vector] || { bg: '#334155', border: '#94a3b8', text: '#f8fafc' };
return {
background: pal.bg,
border: pal.border,
fontColor: pal.text,
highlightBg: pal.bg,
highlightBorder: '#ffffff'
};
}
}
function wrapLabelText(str, maxCharsPerLine = 26) {
if (!str) return '';
const words = str.split(' ');
const lines = [];
let currentLine = '';
words.forEach(word => {
if ((currentLine + ' ' + word).trim().length > maxCharsPerLine) {
if (currentLine) lines.push(currentLine.trim());
currentLine = word;
} else {
currentLine += ' ' + word;
}
});
if (currentLine) lines.push(currentLine.trim());
return lines.slice(0, 3).join('\n');
}
/********************************************************************
* 5. BUILD & RENDER VIS.JS NETWORK
********************************************************************/
function renderVisGraph() {
if (!rawDagData || !rawDagData.nodes) return;
const minScore = parseFloat(document.getElementById('minScoreSlider').value);
const hidePruned = document.getElementById('hidePrunedCheckbox').checked;
const vectorFilter = document.getElementById('vectorFilterSelect').value;
const pillarFilter = document.getElementById('pillarFilterSelect').value;
const visNodes = [];
const visEdges = [];
let totalCount = 0;
let highViabilityCount = 0;
// Determine visibility and dimming for each node
const visibleNodeIds = new Set();
Object.values(rawDagData.nodes).forEach(node => {
totalCount++;
const isRoot = node.hop_depth === 0;
const score = node.composite_score || 0;
if (!isRoot && score >= 7.0) highViabilityCount++;
const passesScore = isRoot || score >= minScore;
const passesVector = isRoot || vectorFilter === 'ALL' || node.applied_vector === vectorFilter;
const passesPillar = isRoot || pillarFilter === 'ALL' || node.mutated_pillar === pillarFilter;
const matchesFilter = passesScore && passesVector && passesPillar;
if (hidePruned && !matchesFilter) {
return; // Skip adding node completely
}
visibleNodeIds.add(node.node_id);
const isDimmed = !matchesFilter;
const palette = getNodeColors(node, isDimmed);
const wrappedTitle = wrapLabelText(node.title, 25);
let label = '';
if (isRoot) {
label = `[ROOT SEED]\n${wrappedTitle}`;
} else {
const vecShort = VECTOR_PALETTE[node.applied_vector]?.short || node.applied_vector;
label = `HOP ${node.hop_depth} | ★ ${score.toFixed(2)}\n${wrappedTitle}\n[${vecShort}]`;
}
visNodes.push({
id: node.node_id,
label: label,
level: node.hop_depth,
shape: 'box',
margin: { top: 10, right: 14, bottom: 10, left: 14 },
borderWidth: isRoot ? 3 : (node.node_id === selectedNodeId ? 3 : 2),
borderWidthSelected: 3,
color: {
background: palette.background,
border: palette.border,
highlight: {
background: palette.highlightBg,
border: '#22d3ee'
},
hover: {
background: palette.highlightBg,
border: palette.highlightBorder
}
},
font: {
color: palette.fontColor,
face: 'Inter, sans-serif',
size: isRoot ? 13 : 12,
multi: false,
align: 'left'
},
shadow: {
enabled: !isDimmed,
color: 'rgba(0,0,0,0.55)',
size: 12,
x: 0,
y: 4
}
});
});
// Build Edges
(rawDagData.edges || []).forEach((edge, idx) => {
if (!visibleNodeIds.has(edge.source) || !visibleNodeIds.has(edge.target)) return;
const targetNode = rawDagData.nodes[edge.target];
const score = targetNode?.composite_score || 0;
const isTargetDimmed =
(score < minScore) ||
(vectorFilter !== 'ALL' && targetNode?.applied_vector !== vectorFilter) ||
(pillarFilter !== 'ALL' && targetNode?.mutated_pillar !== pillarFilter);
const edgeColor = isTargetDimmed
? '#334155'
: (currentColorMode === 'vector' && VECTOR_PALETTE[edge.vector]
? VECTOR_PALETTE[edge.vector].border
: '#64748b');
visEdges.push({
id: `e_${idx}`,
from: edge.source,
to: edge.target,
label: `Δ ${edge.mutated_pillar}`,
font: {
color: isTargetDimmed ? '#475569' : '#94a3b8',
size: 10,
face: 'JetBrains Mono, monospace',
background: '#0b1120',
strokeWidth: 0
},
arrows: {
to: { enabled: true, scaleFactor: 0.7 }
},
color: {
color: edgeColor,
highlight: '#22d3ee',
hover: '#38bdf8'
},
width: isTargetDimmed ? 1 : 2,
dashes: isTargetDimmed ? [5, 5] : false,
smooth: {
type: currentLayoutMode === 'FORCE' ? 'dynamic' : 'cubicBezier',
forceDirection: currentLayoutMode === 'LR' ? 'horizontal' : (currentLayoutMode === 'UD' ? 'vertical' : 'none'),
roundness: 0.45
}
});
});
// Update counters
document.getElementById('statTotalNodes').textContent = totalCount;
document.getElementById('statHighViability').textContent = highViabilityCount;
// Update Vis DataSets
visNodesDataSet.clear();
visEdgesDataSet.clear();
visNodesDataSet.add(visNodes);
visEdgesDataSet.add(visEdges);
const container = document.getElementById('visNetworkContainer');
const options = getVisLayoutOptions();
if (!visNetwork) {
visNetwork = new vis.Network(container, { nodes: visNodesDataSet, edges: visEdgesDataSet }, options);
visNetwork.on('click', (params) => {
if (params.nodes && params.nodes.length > 0) {
selectNode(params.nodes[0]);
}
});
} else {
visNetwork.setOptions(options);
}
updateLegend();
}
function getVisLayoutOptions() {
const isHierarchical = currentLayoutMode === 'LR' || currentLayoutMode === 'UD';
return {
interaction: {
hover: true,
tooltipDelay: 150,
navigationButtons: false,
keyboard: false
},
layout: isHierarchical
? {
hierarchical: {
enabled: true,
direction: currentLayoutMode,
sortMethod: 'directed',
levelSeparation: currentLayoutMode === 'LR' ? 320 : 190,
nodeSpacing: currentLayoutMode === 'LR' ? 115 : 250,
treeSpacing: 140,
blockShifting: true,
edgeMinimization: true,
parentCentralization: true
}
}
: {
hierarchical: { enabled: false }
},
physics: isHierarchical
? { enabled: false }
: {
enabled: true,
barnesHut: {
gravitationalConstant: -7500,
centralGravity: 0.25,
springLength: 210,
springConstant: 0.04,
damping: 0.09
},
stabilization: { iterations: 150 }
}
};
}
/********************************************************************
* 6. DEEP NODE INSPECTOR RENDERING
********************************************************************/
function selectNode(nodeId) {
if (!rawDagData || !rawDagData.nodes[nodeId]) return;
selectedNodeId = nodeId;
const node = rawDagData.nodes[nodeId];
const isRoot = node.hop_depth === 0;
// Highlight in Vis.js
if (visNetwork && visNodesDataSet.get(nodeId)) {
visNetwork.selectNodes([nodeId]);
}
// Update Lineage Breadcrumb
updateLineageBreadcrumb(node);
// Header Badges
const hopBadge = document.getElementById('inspHopBadge');
document.getElementById('inspNodeId').textContent = node.node_id;
if (isRoot) {
hopBadge.textContent = 'HOP 0 • ROOT SEED';
hopBadge.className = 'px-2 py-0.5 rounded text-[11px] font-mono font-semibold bg-indigo-500/20 text-indigo-300 border border-indigo-500/40';
document.getElementById('inspCompositeScore').textContent = 'BASELINE ANCHOR';
document.getElementById('inspCompositeScore').className = 'px-2.5 py-0.5 rounded-md font-mono font-bold text-xs bg-indigo-500/20 text-indigo-300 border border-indigo-500/40';
} else {
hopBadge.textContent = `HOP ${node.hop_depth} • SPIN-OFF`;
hopBadge.className = node.hop_depth === 1
? 'px-2 py-0.5 rounded text-[11px] font-mono font-semibold bg-sky-500/20 text-sky-300 border border-sky-500/40'
: 'px-2 py-0.5 rounded text-[11px] font-mono font-semibold bg-emerald-500/20 text-emerald-300 border border-emerald-500/40';
const score = (node.composite_score || 0).toFixed(2);
const scoreEl = document.getElementById('inspCompositeScore');
scoreEl.textContent = `${score} / 10`;
if (node.composite_score >= 7.5) {
scoreEl.className = 'px-2.5 py-0.5 rounded-md font-mono font-bold text-xs bg-emerald-500/20 text-emerald-300 border border-emerald-500/40';
} else if (node.composite_score >= 5.5) {
scoreEl.className = 'px-2.5 py-0.5 rounded-md font-mono font-bold text-xs bg-amber-500/20 text-amber-300 border border-amber-500/40';
} else {
scoreEl.className = 'px-2.5 py-0.5 rounded-md font-mono font-bold text-xs bg-rose-500/20 text-rose-300 border border-rose-500/40';
}
}
// Title
document.getElementById('inspTitle').textContent = node.title;
// Vector & Archetype Badges
const metaBadges = document.getElementById('inspMetaBadges');
if (isRoot) {
metaBadges.classList.add('hidden');
metaBadges.classList.remove('flex');
} else {
metaBadges.classList.remove('hidden');
metaBadges.classList.add('flex');
document.getElementById('inspVectorBadge').textContent = node.applied_vector || 'N/A';
document.getElementById('inspMoveBadge').textContent = node.archetypal_move || 'N/A';
}
// Summary / Concrete Scenario
document.getElementById('inspSummaryHeader').textContent = isRoot
? 'First-Principles Deconstruction (Jargon Stripped)'
: 'Concrete Deployment Scenario & Target Substrate';
document.getElementById('inspSummaryText').textContent = isRoot
? node.domain_jargon_stripped_summary
: node.concrete_application_scenario;
// Mutation Diff Box
const diffBox = document.getElementById('inspMutationDiffBox');
if (isRoot) {
diffBox.classList.add('hidden');
} else {
diffBox.classList.remove('hidden');
const mutatedKey = node.mutated_pillar;
document.getElementById('inspMutatedPillarTag').textContent = mutatedKey;
document.getElementById('inspMutationExplanation').textContent = node.mutation_delta_explanation || '';
const parentNode = rawDagData.nodes[node.parent_id];
document.getElementById('inspParentIdLabel').textContent = node.parent_id || 'parent';
const parentPrimitives = parentNode
? (parentNode.primitives || parentNode.updated_primitives || {})
: {};
const childPrimitives = node.updated_primitives || {};
document.getElementById('inspParentPillarText').textContent =
parentPrimitives[mutatedKey] || 'N/A';
document.getElementById('inspChildPillarText').textContent =
childPrimitives[mutatedKey] || 'N/A';
}
// Render the 4 Functional Primitives Cards
renderPrimitivesCards(node);
// Render Friction Delta Rubric
const frictionSec = document.getElementById('inspFrictionSection');
if (isRoot || !node.friction_delta) {
frictionSec.classList.add('hidden');
} else {
frictionSec.classList.remove('hidden');
const fd = node.friction_delta;
document.getElementById('inspRubricTotal').textContent = `${(node.composite_score || 0).toFixed(2)} / 10`;
document.getElementById('scorePainText').textContent = `${fd.pain_severity_score} / 10`;
document.getElementById('scorePainBar').style.width = `${fd.pain_severity_score * 10}%`;
document.getElementById('scoreFeasText').textContent = `${fd.technical_feasibility_score} / 10`;
document.getElementById('scoreFeasBar').style.width = `${fd.technical_feasibility_score * 10}%`;
document.getElementById('scoreBarrierText').textContent = `${fd.regulatory_or_adoption_barrier_reduction} / 10`;
document.getElementById('scoreBarrierBar').style.width = `${fd.regulatory_or_adoption_barrier_reduction * 10}%`;
document.getElementById('inspPhysicsCheck').textContent = fd.physics_or_logic_violation_check || 'Verified.';
}
// Render Downstream Children List
renderChildrenButtons(nodeId);
lucide.createIcons();
}
function renderPrimitivesCards(node) {
const container = document.getElementById('inspPrimitivesList');
container.innerHTML = '';
const isRoot = node.hop_depth === 0;
const primitives = isRoot ? node.primitives : node.updated_primitives;
if (!primitives) return;
const pillarKeys = ['input_signal', 'core_mechanism', 'governing_constraint', 'output_value'];
pillarKeys.forEach(key => {
const isMutated = !isRoot && node.mutated_pillar === key;
const card = document.createElement('div');
if (isMutated) {
card.className = 'rounded-xl p-3 bg-amber-950/30 border-2 border-amber-500/60 shadow-inner transition';
card.innerHTML = `
<div class="flex items-center justify-between mb-1">
<span class="font-mono text-xs font-bold text-amber-300 flex items-center gap-1.5">
<i data-lucide="zap" class="w-3.5 h-3.5 text-amber-400"></i>
${PILLAR_LABELS[key]} (<code class="text-[11px]">${key}</code>)
</span>
<span class="px-2 py-0.5 rounded text-[10px] font-mono font-bold bg-amber-500 text-slate-950 uppercase">
MUTATED (1-HOP)
</span>
</div>
<p class="text-xs text-amber-100 leading-relaxed">${primitives[key] || ''}</p>
`;
} else {
card.className = 'rounded-xl p-3 bg-slate-950/70 border border-slate-800/90 transition';
card.innerHTML = `
<div class="flex items-center justify-between mb-1">
<span class="font-mono text-xs font-medium text-slate-300 flex items-center gap-1.5">
<i data-lucide="lock" class="w-3 h-3 text-slate-500"></i>
${PILLAR_LABELS[key]} (<code class="text-[11px] text-slate-400">${key}</code>)
</span>
<span class="px-2 py-0.5 rounded text-[10px] font-mono bg-slate-800 text-slate-400 border border-slate-700">
${isRoot ? 'BASELINE PILLAR' : 'LOCKED INVARIANT'}
</span>
</div>
<p class="text-xs text-slate-400 leading-relaxed">${primitives[key] || ''}</p>
`;
}
container.appendChild(card);
});
}
function renderChildrenButtons(parentId) {
const children = Object.values(rawDagData.nodes).filter(n => n.parent_id === parentId);
const countEl = document.getElementById('inspChildrenCount');
const listEl = document.getElementById('inspChildrenList');
const secEl = document.getElementById('inspChildrenSection');
countEl.textContent = children.length;
listEl.innerHTML = '';
if (children.length === 0) {
secEl.classList.add('hidden');
return;
}
secEl.classList.remove('hidden');
children.forEach(child => {
const btn = document.createElement('button');
const score = (child.composite_score || 0).toFixed(2);
btn.onclick = () => {
selectNode(child.node_id);
if (visNetwork) {
visNetwork.focus(child.node_id, { scale: 1.05, animation: { duration: 400, easingFunction: 'easeInOutQuad' } });
}
};
btn.className = 'w-full text-left px-3 py-2 rounded-lg bg-slate-950 hover:bg-slate-800 border border-slate-800 hover:border-cyan-500/40 flex items-center justify-between gap-2 transition group';
btn.innerHTML = `
<div class="truncate">
<div class="text-xs font-medium text-slate-200 group-hover:text-cyan-300 truncate">${child.title}</div>
<div class="text-[10px] font-mono text-slate-500">${child.applied_vector} • Δ ${child.mutated_pillar}</div>
</div>
<span class="shrink-0 px-2 py-0.5 rounded font-mono text-[11px] font-semibold bg-slate-900 text-cyan-400 border border-slate-700">
★ ${score}
</span>
`;
listEl.appendChild(btn);
});
}
function updateLineageBreadcrumb(node) {
const chain = [node.node_id];
let curr = node;
while (curr.parent_id && rawDagData.nodes[curr.parent_id]) {
chain.unshift(curr.parent_id);
curr = rawDagData.nodes[curr.parent_id];
}
document.getElementById('breadcrumbText').innerHTML = chain
.map(id => `<button onclick="selectNode('${id}')" class="hover:underline hover:text-white">${id}</button>`)
.join(' <span class="text-slate-600">→</span> ');
}
/********************************************************************
* 7. TOOLBAR & LEGEND INTERACTIONS
********************************************************************/
function setColorMode(mode) {
currentColorMode = mode;
const modes = {
viability: document.getElementById('modeViabilityBtn'),
hop: document.getElementById('modeHopBtn'),
vector: document.getElementById('modeVectorBtn')
};
Object.keys(modes).forEach(k => {
if (k === mode) {
modes[k].className = 'px-3 py-1.5 rounded-md text-xs font-medium transition-all flex items-center gap-1.5 bg-cyan-600 text-white shadow';
} else {
modes[k].className = 'px-3 py-1.5 rounded-md text-xs font-medium transition-all flex items-center gap-1.5 text-slate-400 hover:text-slate-200';
}
});
renderVisGraph();
}
function setLayoutMode(layout) {
currentLayoutMode = layout;
const btns = {
LR: document.getElementById('layoutLRBtn'),
UD: document.getElementById('layoutUDBtn'),
FORCE: document.getElementById('layoutForceBtn')
};
Object.keys(btns).forEach(k => {
if (k === layout) {
btns[k].className = 'px-2.5 py-1 rounded bg-slate-800 text-cyan-400 font-mono font-medium transition';
} else {
btns[k].className = 'px-2.5 py-1 rounded text-slate-400 hover:text-slate-200 font-mono transition';
}
});
renderVisGraph();
setTimeout(() => fitGraph(), 200);
}
function applyFilters() {
const val = parseFloat(document.getElementById('minScoreSlider').value).toFixed(2);
document.getElementById('minScoreValue').textContent = val;
renderVisGraph();
}
function updateLegend() {
const legendEl = document.getElementById('legendContent');
if (currentColorMode === 'viability') {
legendEl.innerHTML = `
<span class="font-mono uppercase text-slate-400 font-semibold">Viability Heatmap:</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-indigo-900 border border-indigo-400 inline-block"></span>Root Seed</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-emerald-900 border border-emerald-400 inline-block"></span>Elite (≥8.2)</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-sky-900 border border-sky-400 inline-block"></span>Strong (7.0–8.1)</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-amber-900 border border-amber-400 inline-block"></span>Moderate (5.5–6.9)</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-rose-900 border border-rose-400 inline-block"></span>Pruned (<5.5)</span>
`;
} else if (currentColorMode === 'hop') {
legendEl.innerHTML = `
<span class="font-mono uppercase text-slate-400 font-semibold">Hop Depth Hierarchy:</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-indigo-900 border border-indigo-400 inline-block"></span>Hop 0: Baseline Root</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-sky-950 border border-sky-400 inline-block"></span>Hop 1: First-Order Spin-Off</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-emerald-950 border border-emerald-400 inline-block"></span>Hop 2: Second-Order Frontier</span>
`;
} else {
legendEl.innerHTML = Object.entries(VECTOR_PALETTE).map(([vec, pal]) => `
<span class="flex items-center gap-1.5">
<span class="w-3 h-3 rounded-sm inline-block" style="background:${pal.bg}; border:1px solid ${pal.border}"></span>
<span>${pal.short}</span>
</span>
`).join('');
}
}
function fitGraph() {
if (visNetwork) {
visNetwork.fit({ animation: { duration: 400, easingFunction: 'easeInOutQuad' } });
}
}
function zoomGraph(factor) {
if (!visNetwork) return;
const currentScale = visNetwork.getScale();
visNetwork.moveTo({ scale: currentScale * factor, animation: { duration: 200 } });
}
/********************************************************************
* 8. FILE UPLOAD, DRAG-AND-DROP, PASTE MODAL & EXPORT
********************************************************************/
function handleFileSelect(event) {
const file = event.target.files[0];
if (!file) return;
readJsonFile(file);
}
function readJsonFile(file) {
const reader = new FileReader();
reader.onload = (e) => {
try {
const parsed = JSON.parse(e.target.result);
loadCustomDagObject(parsed, file.name);
} catch (err) {
showToast(`Invalid JSON file: ${err.message}`, true);
}
};
reader.readAsText(file);
}
function setupDragAndDrop() {
const wrapper = document.getElementById('canvasWrapper');
const overlay = document.getElementById('dropOverlay');
wrapper.addEventListener('dragover', (e) => {
e.preventDefault();
overlay.classList.remove('hidden');
});
wrapper.addEventListener('dragleave', (e) => {
e.preventDefault();
overlay.classList.add('hidden');
});
wrapper.addEventListener('drop', (e) => {
e.preventDefault();
overlay.classList.add('hidden');
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
readJsonFile(e.dataTransfer.files[0]);
}
});
}
function loadCustomDagObject(parsed, sourceLabel = 'Custom JSON') {
if (!parsed || typeof parsed.nodes !== 'object') {
throw new Error('JSON must contain a top-level "nodes" dictionary.');
}
// If edges array is missing, reconstruct edges from parent_id references
if (!Array.isArray(parsed.edges)) {
parsed.edges = [];
Object.values(parsed.nodes).forEach(n => {
if (n.parent_id && parsed.nodes[n.parent_id]) {
parsed.edges.push({
source: n.parent_id,
target: n.node_id,
vector: n.applied_vector || '',
mutated_pillar: n.mutated_pillar || ''
});
}
});
}
rawDagData = parsed;
normalizeAndValidateDAG(rawDagData);
const nodeKeys = Object.keys(rawDagData.nodes);
const rootId = rawDagData.nodes['root_0'] ? 'root_0' : nodeKeys[0];
document.getElementById('datasetTitleDisplay').textContent =
`Loaded: ${rawDagData.nodes[rootId]?.title || sourceLabel} (${nodeKeys.length} Nodes)`;
renderVisGraph();
if (rootId) selectNode(rootId);
setTimeout(() => fitGraph(), 250);
showToast(`Loaded ${nodeKeys.length} nodes from ${sourceLabel}`);
}
function openPasteModal() {
const modal = document.getElementById('pasteModal');
const textarea = document.getElementById('jsonPasteTextarea');
document.getElementById('jsonErrorBanner').classList.add('hidden');
textarea.value = JSON.stringify(rawDagData, null, 2);
modal.classList.remove('hidden');
}
function closePasteModal() {
document.getElementById('pasteModal').classList.add('hidden');
}
function formatModalJSON() {
const textarea = document.getElementById('jsonPasteTextarea');
const errBanner = document.getElementById('jsonErrorBanner');
try {
const obj = JSON.parse(textarea.value);
textarea.value = JSON.stringify(obj, null, 2);
errBanner.classList.add('hidden');
} catch (err) {
errBanner.textContent = `Syntax Error: ${err.message}`;
errBanner.classList.remove('hidden');
}
}
function applyPastedJSON() {
const textarea = document.getElementById('jsonPasteTextarea');
const errBanner = document.getElementById('jsonErrorBanner');
try {
const parsed = JSON.parse(textarea.value);
loadCustomDagObject(parsed, 'Pasted JSON');
closePasteModal();
} catch (err) {
errBanner.textContent = `Validation Error: ${err.message}`;
errBanner.classList.remove('hidden');
}
}
function exportFilteredJSON() {
if (!rawDagData) return;
const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(rawDagData, null, 2));
const dlAnchor = document.createElement('a');
dlAnchor.setAttribute("href", dataStr);
dlAnchor.setAttribute("download", "adjacency_idea_dag.json");
document.body.appendChild(dlAnchor);
dlAnchor.click();
dlAnchor.remove();
showToast("Exported adjacency_idea_dag.json");
}
function showToast(msg, isError = false) {
const banner = document.getElementById('toastBanner');
const text = document.getElementById('toastMessage');
text.textContent = msg;
banner.className = `fixed bottom-14 left-1/2 -translate-x-1/2 px-4 py-2 rounded-xl bg-slate-900/95 border ${
isError ? 'border-rose-500/60 text-rose-200' : 'border-cyan-500/40 text-cyan-200'
} text-xs font-mono shadow-2xl z-50 transition-all duration-300 opacity-100 flex items-center gap-2`;
setTimeout(() => {
banner.classList.replace('opacity-100', 'opacity-0');
}, 3200);
}
</script>
</body>
</html>
CODE (DAG for 1st to 3rd Generation Adjacency)
<!DOCTYPE html>
<html lang="en" class="dark">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Adjacency DAG Explorer — Gen 0 to Gen 3 Multi-Generational Viewer</title>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Vis-Network Standalone -->
<script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
<!-- Google Fonts: Inter & JetBrains Mono -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<!-- Lucide Icons -->
<script src="https://unpkg.com/lucide@latest"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'sans-serif'],
mono: ['JetBrains Mono', 'monospace'],
},
colors: {
slate: {
850: '#151f32',
950: '#090e17',
}
}
}
}
}
</script>
<style>
/* Custom scrollbars for dark engineering UI */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: #0f172a;
}
::-webkit-scrollbar-thumb {
background: #334155;
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: #475569;
}
/* Subtle technical grid background for the Vis.js canvas */
.bg-tech-grid {
background-color: #0b1120;
background-image:
linear-gradient(to right, rgba(51, 65, 85, 0.14) 1px, transparent 1px),
linear-gradient(to bottom, rgba(51, 65, 85, 0.14) 1px, transparent 1px);
background-size: 28px 28px;
}
/* Vis-network navigation controls override */
.vis-network:focus {
outline: none;
}
/* Range slider styling */
input[type="range"] {
accent-color: #06b6d4;
}
@keyframes pulse-border {
0%, 100% { border-color: rgba(236, 72, 153, 0.7); }
50% { border-color: rgba(16, 185, 129, 0.9); }
}
.convergent-glow {
animation: pulse-border 3s infinite;
}
</style>
</head>
<body class="bg-slate-950 text-slate-100 font-sans h-screen w-screen overflow-hidden flex flex-col select-none">
<!-- ================= TOP CONTROL BAR ================= -->
<header class="h-auto min-h-[58px] bg-slate-900/95 border-b border-slate-800 px-4 py-2 flex flex-wrap items-center justify-between gap-3 z-20 shrink-0">
<!-- Brand & Dataset Info -->
<div class="flex items-center gap-3">
<div class="w-9 h-9 rounded-lg bg-cyan-500/10 border border-cyan-500/30 flex items-center justify-center text-cyan-400 shadow-inner">
<i data-lucide="git-merge" class="w-5 h-5"></i>
</div>
<div>
<div class="flex items-center gap-2">
<h1 class="font-bold text-sm md:text-base tracking-tight text-white">MULTI-GEN ADJACENCY DAG</h1>
<span class="text-[10px] font-mono uppercase px-2 py-0.5 rounded bg-fuchsia-950 text-fuchsia-300 border border-fuchsia-800/60">Gen 0 → Gen 3 TRIZ</span>
</div>
<p class="text-xs text-slate-400 font-mono truncate max-w-[260px] sm:max-w-md" id="datasetTitleDisplay">
Loaded: 24 GHz FMCW Radar Multi-Gen Trajectory (18 Nodes)
</p>
</div>
</div>
<!-- Color-Coding Mode Switcher -->
<div class="flex items-center bg-slate-950 p-1 rounded-lg border border-slate-800">
<span class="text-[11px] font-mono text-slate-400 px-2 hidden xl:inline">COLOR MODE:</span>
<button id="modeHopBtn" onclick="setColorMode('hop')" class="px-2.5 py-1.5 rounded-md text-xs font-medium transition-all flex items-center gap-1.5 bg-cyan-600 text-white shadow">
<i data-lucide="layers" class="w-3.5 h-3.5"></i>
<span>Gen & Convergence</span>
</button>
<button id="modeViabilityBtn" onclick="setColorMode('viability')" class="px-2.5 py-1.5 rounded-md text-xs font-medium transition-all flex items-center gap-1.5 text-slate-400 hover:text-slate-200">
<i data-lucide="flame" class="w-3.5 h-3.5"></i>
<span>Emergence Score</span>
</button>
<button id="modeVectorBtn" onclick="setColorMode('vector')" class="px-2.5 py-1.5 rounded-md text-xs font-medium transition-all flex items-center gap-1.5 text-slate-400 hover:text-slate-200">
<i data-lucide="compass" class="w-3.5 h-3.5"></i>
<span>6-Vector + TRIZ</span>
</button>
</div>
<!-- File Actions & Layout Controls -->
<div class="flex items-center gap-2">
<!-- Lineage Spotlight Toggle -->
<button id="traceToggleBtn" onclick="toggleLineageSpotlight()" class="px-3 py-1.5 rounded-lg bg-amber-500/20 hover:bg-amber-500/30 border border-amber-500/50 text-amber-300 text-xs font-semibold flex items-center gap-1.5 transition shadow">
<i data-lucide="sparkles" class="w-3.5 h-3.5 text-amber-400"></i>
<span id="traceToggleText">Lineage Spotlight: ON</span>
</button>
<!-- Layout Selector -->
<div class="flex items-center bg-slate-950 rounded-lg border border-slate-800 p-0.5 text-xs">
<button id="layoutLRBtn" onclick="setLayoutMode('LR')" title="Left-to-Right Generational Hierarchy" class="px-2.5 py-1 rounded bg-slate-800 text-cyan-400 font-mono font-medium transition">LR</button>
<button id="layoutUDBtn" onclick="setLayoutMode('UD')" title="Top-Down Generational Hierarchy" class="px-2.5 py-1 rounded text-slate-400 hover:text-slate-200 font-mono transition">UD</button>
<button id="layoutForceBtn" onclick="setLayoutMode('FORCE')" title="Force-Directed Physics Graph" class="px-2.5 py-1 rounded text-slate-400 hover:text-slate-200 font-mono transition">Force</button>
</div>
<!-- Load JSON File Input -->
<label class="cursor-pointer px-2.5 py-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-xs font-medium text-slate-200 flex items-center gap-1.5 transition">
<i data-lucide="upload" class="w-3.5 h-3.5 text-cyan-400"></i>
<span class="hidden sm:inline">Load</span>
<input type="file" id="jsonFileInput" accept=".json" class="hidden" onchange="handleFileSelect(event)" />
</label>
<!-- Paste JSON Modal Trigger -->
<button onclick="openPasteModal()" class="px-2.5 py-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-xs font-medium text-slate-200 flex items-center gap-1.5 transition">
<i data-lucide="code-2" class="w-3.5 h-3.5 text-purple-400"></i>
<span class="hidden md:inline">JSON</span>
</button>
<!-- Export JSON -->
<button onclick="exportFilteredJSON()" title="Export current DAG JSON" class="px-2.5 py-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-xs font-medium text-slate-200 flex items-center gap-1.5 transition">
<i data-lucide="download" class="w-3.5 h-3.5 text-emerald-400"></i>
</button>
<!-- Reset Demo Button -->
<button onclick="loadDemoDataset()" title="Reset to 18-Node Gen 3 FMCW Radar Demo" class="p-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-slate-400 hover:text-white transition">
<i data-lucide="rotate-ccw" class="w-4 h-4"></i>
</button>
</div>
</header>
<!-- ================= SECONDARY FILTER & GEN-3 QUICK JUMP BAR ================= -->
<div class="bg-slate-900/80 border-b border-slate-800/80 px-4 py-1.5 flex flex-wrap items-center justify-between gap-3 text-xs z-10 shrink-0">
<!-- Left Filters -->
<div class="flex flex-wrap items-center gap-3">
<!-- Minimum Viability Score Slider -->
<div class="flex items-center gap-2 bg-slate-950/90 px-2.5 py-1 rounded-lg border border-slate-800">
<span class="text-slate-400 font-medium text-[11px]">Arbiter Gate:</span>
<input type="range" id="minScoreSlider" min="1.0" max="9.5" step="0.25" value="1.0" oninput="applyFilters()" class="w-20 sm:w-24 cursor-pointer" />
<span id="minScoreValue" class="font-mono font-semibold text-cyan-400 w-7 text-right">1.0</span>
<label class="flex items-center gap-1 ml-1.5 pl-1.5 border-l border-slate-800 text-slate-400 cursor-pointer text-[11px]">
<input type="checkbox" id="hidePrunedCheckbox" onchange="applyFilters()" class="rounded bg-slate-900 border-slate-700 text-cyan-500 focus:ring-0" />
<span>Hide</span>
</label>
</div>
<!-- Vector Filter -->
<div class="flex items-center gap-1.5">
<select id="vectorFilterSelect" onchange="applyFilters()" class="bg-slate-950 border border-slate-800 rounded-lg px-2 py-1 text-slate-200 font-medium text-[11px] focus:outline-none focus:border-cyan-500">
<option value="ALL">All Vectors + TRIZ Convergence</option>
<option value="Domain / Substrate Adjacency">1. Domain / Substrate</option>
<option value="Scale / Resolution Adjacency">2. Scale / Resolution</option>
<option value="Temporal / Workflow Adjacency">3. Temporal / Workflow</option>
<option value="Byproduct / Exhaust Adjacency">4. Byproduct / Exhaust</option>
<option value="Constraint / Environment Adjacency">5. Constraint / Environment</option>
<option value="Structural / Topological Inversion">6. Structural Inversion</option>
<option value="TRIZ Cross-Branch Convergence">7. TRIZ Convergent Breeding (2-Parent)</option>
</select>
</div>
<!-- Quick Jump to Gen 3 Breakthroughs -->
<div class="flex items-center gap-1.5 bg-slate-950/90 px-2.5 py-1 rounded-lg border border-slate-800 overflow-x-auto max-w-full">
<span class="text-[10px] font-mono uppercase text-amber-400 font-semibold shrink-0 flex items-center gap-1">
<i data-lucide="zap" class="w-3 h-3"></i>Gen 3 Jump:
</span>
<div id="gen3QuickJumpContainer" class="flex items-center gap-1">
<!-- Populated dynamically with Gen 3 Divergent and Convergent pill buttons -->
</div>
</div>
</div>
<!-- Right Pipeline Telemetry Counters -->
<div class="flex items-center gap-2 font-mono text-[11px]">
<div class="px-2 py-0.5 rounded bg-slate-950 border border-slate-800 text-slate-300">
Nodes: <span id="statTotalNodes" class="text-white font-semibold">18</span>
</div>
<div class="px-2 py-0.5 rounded bg-fuchsia-950/50 border border-fuchsia-700/40 text-fuchsia-300">
Gen 3 Bred: <span id="statConvergentNodes" class="font-semibold">2</span>
</div>
<div id="orthogonalityBadge" class="px-2 py-0.5 rounded bg-emerald-950/60 border border-emerald-700/50 text-emerald-300 flex items-center gap-1">
<i data-lucide="shield-check" class="w-3.5 h-3.5"></i>
<span>Sacred Anchor & Tabu Valid</span>
</div>
</div>
</div>
<!-- ================= MAIN WORKSPACE (CANVAS + INSPECTOR) ================= -->
<div class="flex-1 flex flex-col lg:flex-row overflow-hidden relative">
<!-- LEFT: VIS.JS GRAPH CANVAS AREA -->
<div id="canvasWrapper" class="flex-1 relative bg-tech-grid overflow-hidden flex flex-col">
<!-- Drag & Drop Overlay -->
<div id="dropOverlay" class="hidden absolute inset-0 bg-cyan-950/80 backdrop-blur-sm border-2 border-dashed border-cyan-400 z-30 flex flex-col items-center justify-center pointer-events-none">
<i data-lucide="file-json" class="w-16 h-16 text-cyan-300 mb-3 animate-bounce"></i>
<p class="text-lg font-bold text-white">Drop <code class="font-mono text-cyan-300">adjacency_idea_dag.json</code> to render</p>
<p class="text-xs text-cyan-200 mt-1">Supports Gen 0 → Gen 3 Divergent & Convergent DAG schemas</p>
</div>
<!-- Vis.js Container -->
<div id="visNetworkContainer" class="w-full flex-1"></div>
<!-- Floating Zoom / Fit Controls -->
<div class="absolute top-3 left-3 flex flex-col gap-1.5 z-10">
<button onclick="fitGraph()" title="Fit Full DAG to Screen" class="p-2 rounded-lg bg-slate-900/90 hover:bg-slate-800 text-slate-300 hover:text-white border border-slate-700/80 shadow-lg transition">
<i data-lucide="maximize-2" class="w-4 h-4"></i>
</button>
<button onclick="zoomGraph(1.25)" title="Zoom In" class="p-2 rounded-lg bg-slate-900/90 hover:bg-slate-800 text-slate-300 hover:text-white border border-slate-700/80 shadow-lg transition">
<i data-lucide="zoom-in" class="w-4 h-4"></i>
</button>
<button onclick="zoomGraph(0.8)" title="Zoom Out" class="p-2 rounded-lg bg-slate-900/90 hover:bg-slate-800 text-slate-300 hover:text-white border border-slate-700/80 shadow-lg transition">
<i data-lucide="zoom-out" class="w-4 h-4"></i>
</button>
</div>
<!-- Interactive Lineage Path Floating Banner -->
<div id="lineageBreadcrumb" class="absolute top-3 right-3 max-w-xl bg-slate-900/95 backdrop-blur-md border border-slate-700/80 rounded-xl px-3.5 py-2 text-xs font-mono text-slate-300 flex flex-wrap items-center gap-1.5 shadow-xl z-10">
<span class="text-amber-400 font-semibold flex items-center gap-1">
<i data-lucide="git-commit" class="w-3.5 h-3.5"></i>LINEAGE TRACE:
</span>
<div id="breadcrumbText" class="flex flex-wrap items-center gap-1 text-cyan-300">root_0</div>
</div>
<!-- Bottom Dynamic Legend Bar -->
<div class="bg-slate-900/95 border-t border-slate-800 px-4 py-2 flex flex-wrap items-center justify-between gap-3 text-[11px] z-10">
<div id="legendContent" class="flex flex-wrap items-center gap-3.5">
<!-- Populated dynamically by updateLegend() -->
</div>
<div class="text-slate-400 font-mono hidden xl:flex items-center gap-3">
<span><strong class="text-amber-300">Click Any Node:</strong> Trace Gen 0 → Gen 3 Ancestral Path</span>
</div>
</div>
</div>
<!-- RIGHT: DEEP NODE INSPECTOR SIDEBAR -->
<aside id="inspectorPanel" class="w-full lg:w-[490px] xl:w-[540px] h-[50vh] lg:h-full bg-slate-900 border-t lg:border-t-0 lg:border-l border-slate-800 flex flex-col overflow-hidden shrink-0 z-20">
<!-- Inspector Header -->
<div class="px-5 py-3 bg-slate-950/70 border-b border-slate-800 flex items-center justify-between shrink-0">
<div class="flex items-center gap-2">
<span id="inspHopBadge" class="px-2.5 py-0.5 rounded text-[11px] font-mono font-bold bg-indigo-500/20 text-indigo-300 border border-indigo-500/40">
GEN 0 • ROOT SEED
</span>
<span id="inspNodeId" class="font-mono text-xs text-slate-400">root_0</span>
</div>
<div id="inspScoreContainer" class="flex items-center gap-1.5">
<span class="text-[10px] text-slate-400 font-mono uppercase">EMERGENCE SCORE:</span>
<span id="inspCompositeScore" class="px-2.5 py-0.5 rounded-md font-mono font-bold text-xs bg-emerald-500/20 text-emerald-300 border border-emerald-500/40">
ANCHOR
</span>
</div>
</div>
<!-- Scrollable Inspector Body -->
<div class="flex-1 overflow-y-auto p-5 space-y-4 select-text">
<!-- Node Title & Vector / Archetype Badges -->
<div>
<h2 id="inspTitle" class="text-base sm:text-lg font-bold text-white leading-snug">
24 GHz Automotive Blind-Spot FMCW Radar
</h2>
<!-- Vector & Move Badges (Hidden for Root) -->
<div id="inspMetaBadges" class="hidden flex-wrap gap-2 mt-2.5">
<div class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md bg-slate-800 border border-slate-700 text-xs text-cyan-300">
<i data-lucide="compass" class="w-3.5 h-3.5"></i>
<span id="inspVectorBadge">Domain / Substrate Adjacency</span>
</div>
<div class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md bg-slate-800 border border-slate-700 text-xs text-purple-300">
<i data-lucide="sparkles" class="w-3.5 h-3.5"></i>
<span id="inspMoveBadge">Orthogonal Bridge</span>
</div>
</div>
</div>
<!-- Sacred Anchor & Tabu Memory Verification Strip -->
<div class="bg-emerald-950/25 border border-emerald-500/30 rounded-xl p-3 flex items-start justify-between gap-3">
<div class="space-y-1">
<div class="text-[10px] font-mono uppercase tracking-wider text-emerald-400 font-bold flex items-center gap-1.5">
<i data-lucide="anchor" class="w-3.5 h-3.5"></i>
<span>Sacred Anchor Locked (Gen 0 → Gen 3 Invariant)</span>
</div>
<p class="text-xs text-emerald-100/90 font-mono">
core_mechanism: "Homodyne quadrature mixing + 2D Range-Doppler FFT beat-frequency phase extraction"
</p>
</div>
<span id="inspMutationRatioBadge" class="shrink-0 px-2 py-1 rounded bg-slate-950 border border-emerald-500/40 font-mono text-[11px] text-emerald-300 font-semibold">
0/4 Mutated
</span>
</div>
<!-- FULL MULTI-GEN LINEAGE STEPPER (Gen 0 -> Current Node) -->
<div id="inspLineageStepperSection" class="bg-slate-950/90 border border-slate-800 rounded-xl p-3.5 space-y-2.5">
<div class="flex items-center justify-between">
<span class="text-[11px] font-mono uppercase tracking-wider text-amber-300 font-semibold flex items-center gap-1.5">
<i data-lucide="git-branch" class="w-3.5 h-3.5 text-amber-400"></i>
<span>Generational Trajectory Audit (Tabu Memory)</span>
</span>
<button onclick="focusLineageSubgraph()" class="text-[10px] font-mono px-2 py-0.5 rounded bg-amber-500/15 hover:bg-amber-500/25 text-amber-300 border border-amber-500/30 transition">
Fit Path on Canvas
</button>
</div>
<div id="inspLineageStepsContainer" class="space-y-1.5">
<!-- Populated dynamically with step-by-step hop history -->
</div>
</div>
<!-- TRIZ CONVERGENCE SYNTHESIS CARD (Shown ONLY for Gen 3 Convergent 2-Parent Nodes) -->
<div id="inspConvergenceCard" class="hidden bg-gradient-to-br from-fuchsia-950/40 via-slate-900 to-emerald-950/30 border-2 border-fuchsia-500/50 rounded-xl p-4 space-y-3 convergent-glow">
<div class="flex items-center justify-between">
<span class="text-xs font-mono font-bold uppercase tracking-wider text-fuchsia-300 flex items-center gap-1.5">
<i data-lucide="git-merge" class="w-4 h-4 text-fuchsia-400"></i>
Gen 3 Convergent Breeding (TRIZ Synthesis)
</span>
<span class="px-2 py-0.5 rounded bg-fuchsia-500/20 text-fuchsia-200 font-mono text-[10px] border border-fuchsia-400/40">
2-Parent Recombination
</span>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2.5 text-xs">
<div class="bg-slate-950/85 border border-sky-500/40 rounded-lg p-2.5">
<div class="text-[10px] font-mono text-sky-400 uppercase font-semibold mb-1" id="convParentALabel">Parent A (Gen 2):</div>
<div id="convParentAText" class="text-slate-200 leading-relaxed text-[11px]"></div>
</div>
<div class="bg-slate-950/85 border border-emerald-500/40 rounded-lg p-2.5">
<div class="text-[10px] font-mono text-emerald-400 uppercase font-semibold mb-1" id="convParentBLabel">Parent B (Gen 2):</div>
<div id="convParentBText" class="text-slate-200 leading-relaxed text-[11px]"></div>
</div>
</div>
<div class="bg-slate-950/90 border border-fuchsia-500/40 rounded-lg p-3">
<div class="text-[10px] font-mono text-fuchsia-300 uppercase font-semibold mb-1">
TRIZ Physical Contradiction Resolved:
</div>
<p id="convContradictionText" class="text-xs text-fuchsia-100 leading-relaxed"></p>
</div>
</div>
<!-- Scenario or First-Principles Summary -->
<div class="bg-slate-950/80 border border-slate-800/90 rounded-xl p-3.5">
<div class="text-[11px] font-mono uppercase tracking-wider text-slate-400 mb-1.5 flex items-center gap-1.5">
<i data-lucide="cpu" class="w-3.5 h-3.5 text-cyan-400"></i>
<span id="inspSummaryHeader">First-Principles Deconstruction (Jargon Stripped)</span>
</div>
<p id="inspSummaryText" class="text-xs text-slate-300 leading-relaxed"></p>
</div>
<!-- IMMEDIATE HOP MUTATION DIFF (Hidden on Root) -->
<div id="inspMutationDiffBox" class="hidden bg-amber-950/20 border border-amber-500/30 rounded-xl p-3.5 space-y-2.5">
<div class="flex items-center justify-between">
<span class="text-[11px] font-mono font-semibold uppercase tracking-wider text-amber-300 flex items-center gap-1.5">
<i data-lucide="git-compare" class="w-4 h-4 text-amber-400"></i>
Latest Hop Mutation Delta
</span>
<span id="inspMutatedPillarTag" class="px-2 py-0.5 rounded bg-amber-500/20 text-amber-300 font-mono text-[11px] border border-amber-500/40">
output_value
</span>
</div>
<p id="inspMutationExplanation" class="text-xs text-amber-100/90 leading-relaxed"></p>
<!-- Before vs After Pillar Comparison -->
<div class="grid grid-cols-1 gap-2 pt-1 text-xs">
<div class="bg-slate-950/90 border border-slate-800 rounded-lg p-2.5">
<div class="text-[10px] font-mono text-slate-400 uppercase mb-0.5">
Immediate Parent (<span id="inspParentIdLabel">root_0</span>) State:
</div>
<div id="inspParentPillarText" class="text-slate-400 line-through decoration-rose-500/60"></div>
</div>
<div class="bg-slate-950/90 border border-amber-500/40 rounded-lg p-2.5">
<div class="text-[10px] font-mono text-amber-400 uppercase mb-0.5">
New Mutated Pillar State:
</div>
<div id="inspChildPillarText" class="text-amber-200 font-medium"></div>
</div>
</div>
</div>
<!-- THE 4 FUNCTIONAL PRIMITIVES (CUMULATIVE GENERATIONAL MUTATION MATRIX) -->
<div>
<div class="flex items-center justify-between mb-2">
<h3 class="text-xs font-mono uppercase tracking-wider text-slate-300 font-semibold flex items-center gap-1.5">
<i data-lucide="layers" class="w-3.5 h-3.5 text-cyan-400"></i>
<span>4 Functional Pillars (Cumulative State)</span>
</h3>
<span class="text-[10px] font-mono text-slate-500">Gen 0 → Gen N Audit</span>
</div>
<div id="inspPrimitivesList" class="space-y-2">
<!-- Dynamically populated cards showing which generation mutated each pillar -->
</div>
</div>
<!-- GENERATION-ADJUSTED EMERGENCE SCORE & ENTROPY CHECK (Hidden on Root) -->
<div id="inspFrictionSection" class="hidden bg-slate-950/90 border border-slate-800 rounded-xl p-4 space-y-3.5">
<div class="flex items-center justify-between border-b border-slate-800 pb-2.5">
<div>
<h3 class="text-xs font-mono uppercase tracking-wider text-slate-200 font-semibold">
Generation-Adjusted Emergence Rubric
</h3>
<p class="text-[10px] text-slate-400 font-mono">
Balances Base Viability + Paradigm Novelty (with Gen 3 Feasibility Gate)
</p>
</div>
<div id="inspRubricTotal" class="text-lg font-mono font-bold text-emerald-400">
8.75 / 10
</div>
</div>
<!-- 4 Score Bars (Pain, Feasibility, Barrier Reduction, Paradigm Novelty) -->
<div class="space-y-2 text-xs">
<div>
<div class="flex justify-between mb-1">
<span class="text-slate-300">Pain Severity in Target Niche <span class="text-slate-500 font-mono">(30% Base)</span></span>
<span id="scorePainText" class="font-mono font-semibold text-cyan-300">9 / 10</span>
</div>
<div class="w-full h-1.5 bg-slate-800 rounded-full overflow-hidden">
<div id="scorePainBar" class="h-full bg-cyan-500 rounded-full transition-all duration-300" style="width: 90%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span class="text-slate-300">Technical Feasibility & COTS Readiness <span class="text-slate-500 font-mono">(45% Base)</span></span>
<span id="scoreFeasText" class="font-mono font-semibold text-emerald-300">8 / 10</span>
</div>
<div class="w-full h-1.5 bg-slate-800 rounded-full overflow-hidden">
<div id="scoreFeasBar" class="h-full bg-emerald-500 rounded-full transition-all duration-300" style="width: 80%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span class="text-slate-300">Regulatory / Adoption Barrier Reduction <span class="text-slate-500 font-mono">(25% Base)</span></span>
<span id="scoreBarrierText" class="font-mono font-semibold text-purple-300">8 / 10</span>
</div>
<div class="w-full h-1.5 bg-slate-800 rounded-full overflow-hidden">
<div id="scoreBarrierBar" class="h-full bg-purple-500 rounded-full transition-all duration-300" style="width: 80%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span class="text-amber-300 font-medium">Paradigm Novelty vs. Gen 0 <span class="text-amber-500/80 font-mono">(Gen 2: 25%, Gen 3: 40%)</span></span>
<span id="scoreNoveltyText" class="font-mono font-semibold text-amber-300">10 / 10</span>
</div>
<div class="w-full h-1.5 bg-slate-800 rounded-full overflow-hidden">
<div id="scoreNoveltyBar" class="h-full bg-amber-400 rounded-full transition-all duration-300" style="width: 100%"></div>
</div>
</div>
</div>
<!-- Physics / Compound Entropy Verification Check -->
<div class="pt-2 border-t border-slate-800/80">
<div class="text-[10px] font-mono uppercase text-emerald-400 mb-1 flex items-center gap-1">
<i data-lucide="check-circle-2" class="w-3.5 h-3.5"></i>
<span>Compound Entropy & Scaling Law Check</span>
</div>
<p id="inspPhysicsCheck" class="text-xs text-slate-300 font-mono bg-slate-900/90 p-2.5 rounded-lg border border-slate-800 leading-relaxed"></p>
</div>
</div>
<!-- Immediate Children / Downstream Branches Quick Jump -->
<div id="inspChildrenSection" class="pt-1">
<div class="text-[11px] font-mono uppercase tracking-wider text-slate-400 mb-2">
Downstream Adjacency Branches (<span id="inspChildrenCount">6</span>)
</div>
<div id="inspChildrenList" class="grid grid-cols-1 gap-1.5">
<!-- Dynamically populated buttons to jump to child nodes -->
</div>
</div>
</div>
</aside>
</div>
<!-- ================= PASTE / EDIT JSON MODAL ================= -->
<div id="pasteModal" class="hidden fixed inset-0 bg-slate-950/80 backdrop-blur-sm z-50 flex items-center justify-center p-4">
<div class="bg-slate-900 border border-slate-700 rounded-2xl max-w-3xl w-full flex flex-col max-h-[85vh] shadow-2xl overflow-hidden">
<div class="px-5 py-3.5 bg-slate-950 border-b border-slate-800 flex items-center justify-between">
<div class="flex items-center gap-2">
<i data-lucide="file-json" class="w-5 h-5 text-cyan-400"></i>
<h3 class="font-bold text-sm text-white">Load or Edit <code class="font-mono text-cyan-300">adjacency_idea_dag.json</code></h3>
</div>
<button onclick="closePasteModal()" class="text-slate-400 hover:text-white">
<i data-lucide="x" class="w-5 h-5"></i>
</button>
</div>
<div class="p-5 flex-1 flex flex-col gap-3 overflow-hidden">
<p class="text-xs text-slate-400">
Paste the JSON output generated by <code class="font-mono text-slate-200">AdjacencyBranchingEngine.export_dag_json()</code> below. The viewer automatically validates <code class="font-mono text-slate-200">composite_score</code> and checks 2-hop orthogonality constraints.
</p>
<div id="jsonErrorBanner" class="hidden px-3 py-2 rounded-lg bg-rose-950/90 border border-rose-500/50 text-rose-200 text-xs font-mono"></div>
<textarea id="jsonPasteTextarea" spellcheck="false" class="w-full flex-1 bg-slate-950 border border-slate-800 rounded-xl p-3.5 font-mono text-xs text-slate-200 focus:outline-none focus:border-cyan-500 resize-none"></textarea>
</div>
<div class="px-5 py-3 bg-slate-950 border-t border-slate-800 flex items-center justify-between">
<button onclick="formatModalJSON()" class="px-3 py-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 text-xs font-mono text-slate-300 transition">
Prettify JSON
</button>
<div class="flex items-center gap-2">
<button onclick="closePasteModal()" class="px-4 py-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 text-xs font-medium text-slate-300 transition">
Cancel
</button>
<button onclick="applyPastedJSON()" class="px-4 py-1.5 rounded-lg bg-cyan-600 hover:bg-cyan-500 text-xs font-semibold text-white shadow transition">
Render DAG Graph
</button>
</div>
</div>
</div>
</div>
<!-- ================= TOAST NOTIFICATION ================= -->
<div id="toastBanner" class="fixed bottom-14 left-1/2 -translate-x-1/2 px-4 py-2 rounded-xl bg-slate-900/95 border border-cyan-500/40 text-xs font-mono text-cyan-200 shadow-2xl z-50 transition-all duration-300 opacity-0 pointer-events-none flex items-center gap-2">
<i data-lucide="info" class="w-4 h-4 text-cyan-400"></i>
<span id="toastMessage">Loaded DAG</span>
</div>
<!-- ================= APPLICATION JAVASCRIPT ================= -->
<script>
/********************************************************************
* 1. BUILT-IN 18-NODE MULTI-GENERATIONAL DATASET (Gen 0 -> Gen 3)
* Includes:
* - 1 Gen 0 Root Seed (24 GHz Automotive Blind-Spot FMCW Radar)
* - 6 Gen 1 Spin-Offs (1 per Adjacency Vector)
* - 6 Gen 2 Orthogonal Branches (2 Pillars Mutated, 2 Locked)
* - 3 Gen 3 Divergent Nodes (3 Pillars Mutated, Sacred Anchor Locked)
* - 2 Gen 3 Convergent (2-Parent TRIZ Recombination) Breakthroughs
********************************************************************/
const DEMO_DAG_DATA = {
"nodes": {
/* ==================== GENERATION 0 (ROOT SEED) ==================== */
"root_0": {
"node_id": "root_0",
"parent_ids": [],
"hop_depth": 0,
"node_type": "root",
"title": "24 GHz Automotive Blind-Spot FMCW Radar",
"domain_jargon_stripped_summary": "Synthesizes linear frequency-modulated continuous-wave (FMCW) millimeter-wave sweeps, mixes reflected echoes with the local oscillator to extract intermediate beat frequencies, and computes target range/velocity/phase matrices via 2D Fast Fourier Transform.",
"primitives": {
"input_signal": "24 GHz millimeter-wave electromagnetic chirp reflecting off metallic vehicles in outdoor highway line-of-sight.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat-frequency phase-shift extraction.",
"governing_constraint": "Automotive bumper thermal envelope (-40C to 105C), highway multipath clutter, and <50ms AEB braking latency.",
"output_value": "Real-time obstacle range/velocity vector to trigger Automatic Emergency Braking (AEB) or blind-spot warning."
},
"pillar_mutation_history": {
"input_signal": 0,
"core_mechanism": 0,
"governing_constraint": 0,
"output_value": 0
}
},
/* ==================== GENERATION 1 (6 ORTHOGONAL VECTORS) ==================== */
"hop1_v1": {
"node_id": "hop1_v1",
"parent_id": "root_0",
"parent_ids": ["root_0"],
"hop_depth": 1,
"node_type": "divergent",
"applied_vector": "Domain / Substrate Adjacency",
"archetypal_move": "Orthogonal Bridge (2-Node Recombination)",
"mutated_pillar": "input_signal",
"locked_pillars": ["core_mechanism", "governing_constraint", "output_value"],
"mutation_delta_explanation": "Swaps the propagation medium from open-air highway metal reflections to through-drywall indoor rooms, capturing sub-millimeter human thoracic skin micro-Doppler reflections.",
"title": "Through-Wall Non-Contact Cardiopulmonary Apnea & Fall Radar",
"updated_primitives": {
"input_signal": "24 GHz RF chirp penetrating gypsum drywall/bedding and reflecting off sub-millimeter human chest wall motion.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat-frequency phase-shift extraction.",
"governing_constraint": "Indoor FCC Part 15 EIRP limits, clutter rejection from ceiling fans, and <50ms fall trajectory latency.",
"output_value": "Real-time respiratory/cardiac phase waveform and immediate elder fall alert vector without cameras."
},
"pillar_mutation_history": { "input_signal": 1, "core_mechanism": 0, "governing_constraint": 0, "output_value": 0 },
"concrete_application_scenario": "Ceiling-mounted behind-drywall sensor in memory-care facilities and NICUs monitoring sleep apnea and bed-exit falls with zero optical privacy intrusion.",
"friction_delta": {
"pain_severity_score": 9,
"technical_feasibility_score": 9,
"regulatory_or_adoption_barrier_reduction": 8,
"paradigm_novelty_score": 7,
"physics_or_logic_violation_check": "PASS: At 24 GHz (lambda=12.5mm), a 0.5mm chest displacement yields a 28.8-deg phase shift, easily resolved via arctangent demodulation."
},
"composite_score": 8.75
},
"hop1_v2": {
"node_id": "hop1_v2",
"parent_id": "root_0",
"parent_ids": ["root_0"],
"hop_depth": 1,
"node_type": "divergent",
"applied_vector": "Scale / Resolution Adjacency",
"archetypal_move": "Orthogonal Bridge (2-Node Recombination)",
"mutated_pillar": "governing_constraint",
"locked_pillars": ["input_signal", "core_mechanism", "output_value"],
"mutation_delta_explanation": "Compresses spatial operating range by 3 orders of magnitude (from 150m highway down to 20mm near-field waveguide) to resolve sub-millimeter internal dielectric voids inside solid composite slabs.",
"title": "Near-Field Millimeter-Wave Sub-Surface Composite Void Scanner",
"updated_primitives": {
"input_signal": "Swept millimeter-wave chirp coupled into glass-fiber composite laminates or cured dielectric slabs.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat-frequency phase-shift extraction.",
"governing_constraint": "Near-field standoff distance (<20mm) and dielectric attenuation depth limit (~4cm) rather than highway multipath.",
"output_value": "Real-time sub-surface delamination, void, and moisture defect vector for non-destructive testing (NDT)."
},
"pillar_mutation_history": { "input_signal": 0, "core_mechanism": 0, "governing_constraint": 1, "output_value": 0 },
"concrete_application_scenario": "Robotic gantry scanner inspecting wind turbine blades and aerospace radomes for micro-delamination without ultrasound couplant gels.",
"friction_delta": {
"pain_severity_score": 8,
"technical_feasibility_score": 8,
"regulatory_or_adoption_barrier_reduction": 9,
"paradigm_novelty_score": 7,
"physics_or_logic_violation_check": "PASS: Non-conductive GFRP/epoxy is transparent at 24-60 GHz; refractive index contrast at air voids produces strong phase spikes."
},
"composite_score": 8.25
},
"hop1_v3": {
"node_id": "hop1_v3",
"parent_id": "root_0",
"parent_ids": ["root_0"],
"hop_depth": 1,
"node_type": "divergent",
"applied_vector": "Temporal / Workflow Adjacency",
"archetypal_move": "Pickaxe Extraction (Internal Scaffolding)",
"mutated_pillar": "output_value",
"locked_pillars": ["input_signal", "core_mechanism", "governing_constraint"],
"mutation_delta_explanation": "Shifts upstream in the radar manufacturing workflow: extracts the internal end-of-line Doppler target simulator rig and packages it as a compact body-shop ADAS calibration appliance.",
"title": "Portable Electronic Radar Target Simulator (RTS) Calibration Box",
"updated_primitives": {
"input_signal": "24/77 GHz chirp emitted by a vehicle bumper radar undergoing post-collision repair.",
"core_mechanism": "Homodyne quadrature mixing + digital phase-shift delay line re-transmitting synthetic ghost echoes.",
"governing_constraint": "Automotive body-shop floor space (<2m bay) and <1ns phase-coherent repeater latency.",
"output_value": "Certified ADAS calibration pass/fail cryptographic receipt for insurance compliance."
},
"pillar_mutation_history": { "input_signal": 0, "core_mechanism": 0, "governing_constraint": 0, "output_value": 1 },
"concrete_application_scenario": "Compact tripod box allowing independent auto body shops to recalibrate ADAS radars in a 3m bay instead of a 30m hall.",
"friction_delta": {
"pain_severity_score": 9,
"technical_feasibility_score": 8,
"regulatory_or_adoption_barrier_reduction": 7,
"paradigm_novelty_score": 6,
"physics_or_logic_violation_check": "PASS: Digital RF memory (DRFM) and switched delay lines synthesize virtual targets from 2m to 150m."
},
"composite_score": 8.05
},
"hop1_v4": {
"node_id": "hop1_v4",
"parent_id": "root_0",
"parent_ids": ["root_0"],
"hop_depth": 1,
"node_type": "divergent",
"applied_vector": "Byproduct / Exhaust Adjacency",
"archetypal_move": "Symbiotic Parasite (Host Attachment)",
"mutated_pillar": "output_value",
"locked_pillars": ["input_signal", "core_mechanism", "governing_constraint"],
"mutation_delta_explanation": "Repurposes the rejected 'ground-clutter backscatter noise floor' (normally discarded by AEB filters) into a real-time road surface black-ice and water-film classifier.",
"title": "Backscatter Clutter Road-Surface Black-Ice & Hydroplane Classifier",
"updated_primitives": {
"input_signal": "24 GHz grazing-angle radar chirp reflecting off asphalt immediately ahead of the vehicle bumper.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT analyzing phase & spectral kurtosis of discarded ground clutter.",
"governing_constraint": "Automotive bumper thermal envelope (-40C to 105C) and <50ms traction ECU telemetry latency.",
"output_value": "Continuous road friction coefficient (dry asphalt, water film depth, black ice) fed to ABS/torque-vectoring ECU."
},
"pillar_mutation_history": { "input_signal": 0, "core_mechanism": 0, "governing_constraint": 0, "output_value": 1 },
"concrete_application_scenario": "Zero-hardware firmware upgrade for fleet trucks turning discarded radar ground-clutter into a localized black-ice warning stream.",
"friction_delta": {
"pain_severity_score": 7,
"technical_feasibility_score": 8,
"regulatory_or_adoption_barrier_reduction": 8,
"paradigm_novelty_score": 7,
"physics_or_logic_violation_check": "PASS: Liquid water and crystalline ice exhibit distinct complex permittivity at 24 GHz, altering Bragg backscatter phase."
},
"composite_score": 7.70
},
"hop1_v5": {
"node_id": "hop1_v5",
"parent_id": "root_0",
"parent_ids": ["root_0"],
"hop_depth": 1,
"node_type": "divergent",
"applied_vector": "Constraint / Environment Adjacency",
"archetypal_move": "Passive / Active Energy Flip",
"mutated_pillar": "governing_constraint",
"locked_pillars": ["input_signal", "core_mechanism", "output_value"],
"mutation_delta_explanation": "Forces the target environment to operate at zero onboard battery power (ATEX explosive atmospheres) by separating the active FMCW interrogator from passive chipless acoustic-wave reflectors on targets.",
"title": "Zero-Power Chipless SAW Harmonic Reflector Tag for Explosive Zones",
"updated_primitives": {
"input_signal": "24 GHz electromagnetic sweep illuminating dust-obscured subterranean tunnels and passive target tags.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat-frequency phase-shift extraction of passive delay echoes.",
"governing_constraint": "Zero onboard electrical energy on the target (ATEX intrinsic safety in methane/coal dust) and extreme vibration.",
"output_value": "Real-time obstacle/personnel range and ID vector for automated haul trucks in GPS-denied mines."
},
"pillar_mutation_history": { "input_signal": 0, "core_mechanism": 0, "governing_constraint": 1, "output_value": 0 },
"concrete_application_scenario": "Battery-free collision avoidance tags bolted to underground mining vests, valves, and ventilation bulkheads.",
"friction_delta": {
"pain_severity_score": 8,
"technical_feasibility_score": 7,
"regulatory_or_adoption_barrier_reduction": 8,
"paradigm_novelty_score": 7,
"physics_or_logic_violation_check": "PASS: Passive Van Atta retrodirective arrays + SAW delay lines maintain readable RCS up to 25m without active power."
},
"composite_score": 7.55
},
"hop1_v6": {
"node_id": "hop1_v6",
"parent_id": "root_0",
"parent_ids": ["root_0"],
"hop_depth": 1,
"node_type": "divergent",
"applied_vector": "Structural / Topological Inversion",
"archetypal_move": "Symbiotic Parasite (Host Attachment)",
"mutated_pillar": "input_signal",
"locked_pillars": ["core_mechanism", "governing_constraint", "output_value"],
"mutation_delta_explanation": "Inverts the moving vs. stationary topology: mounts stationary radars looking across enclosed gravity chutes while dense curtains of bulk ore/grain fall past.",
"title": "Gravity-Chute Bulk Solids Mass-Flow & Velocity Stall Interferometer",
"updated_primitives": {
"input_signal": "24 GHz FMCW chirp illuminating a falling curtain of bulk grain, cement clinker, or crushed ore inside a steel chute.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat-frequency phase-shift extraction.",
"governing_constraint": "Opaque abrasive dust clouds, thermal swings, and <50ms chute-plugging diverter latency.",
"output_value": "Real-time mass velocity vector and immediate pneumatic gate trigger before chute blockage occurs."
},
"pillar_mutation_history": { "input_signal": 1, "core_mechanism": 0, "governing_constraint": 0, "output_value": 0 },
"concrete_application_scenario": "Mounted outside an HDPE window on grain elevators and mining crushers where optical lasers blind in 10 seconds.",
"friction_delta": {
"pain_severity_score": 8,
"technical_feasibility_score": 9,
"regulatory_or_adoption_barrier_reduction": 9,
"paradigm_novelty_score": 7,
"physics_or_logic_violation_check": "PASS: 24 GHz penetrates dense silica/grain dust effortlessly since particle diameter (0.1mm) << wavelength (12.5mm)."
},
"composite_score": 8.70
},
/* ==================== GENERATION 2 (6 ORTHOGONAL 2-HOP NODES) ==================== */
"hop1_v1_hop2_1": {
"node_id": "hop1_v1_hop2_1",
"parent_id": "hop1_v1",
"parent_ids": ["hop1_v1"],
"hop_depth": 2,
"node_type": "divergent",
"applied_vector": "Byproduct / Exhaust Adjacency",
"archetypal_move": "Symbiotic Parasite (Host Attachment)",
"mutated_pillar": "output_value",
"locked_pillars": ["input_signal", "core_mechanism", "governing_constraint"],
"mutation_delta_explanation": "Locks the indoor through-wall 24 GHz bio-radar input from Hop 1, but mutates output_value to harvest aggregate human respiratory metabolic load for predictive HVAC damper control.",
"title": "Metabolic-Load HVAC Ventilation Controller via Micro-Doppler Respiration",
"updated_primitives": {
"input_signal": "24 GHz RF chirp penetrating gypsum drywall and reflecting off human thoracic motion in commercial buildings.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat-frequency phase-shift extraction.",
"governing_constraint": "Indoor FCC Part 15 EIRP limits, ceiling fan clutter rejection, and BACnet building bus latency.",
"output_value": "Exact static occupant headcount + aggregate metabolic breathing rate to modulate VAV airflow dampers 20 mins before CO2 spikes."
},
"pillar_mutation_history": { "input_signal": 1, "core_mechanism": 0, "governing_constraint": 0, "output_value": 2 },
"concrete_application_scenario": "Replaces lagging wall CO2 sensors and blind PIR motion sensors in commercial office buildings and lecture halls.",
"friction_delta": {
"pain_severity_score": 8,
"technical_feasibility_score": 9,
"regulatory_or_adoption_barrier_reduction": 10,
"paradigm_novelty_score": 8,
"physics_or_logic_violation_check": "PASS: Eliminates FDA medical device clearance while using 100% identical RF physics to hop1_v1."
},
"composite_score": 8.71
},
"hop1_v1_hop2_2": {
"node_id": "hop1_v1_hop2_2",
"parent_id": "hop1_v1",
"parent_ids": ["hop1_v1"],
"hop_depth": 2,
"node_type": "divergent",
"applied_vector": "Constraint / Environment Adjacency",
"archetypal_move": "Orthogonal Bridge (2-Node Recombination)",
"mutated_pillar": "governing_constraint",
"locked_pillars": ["input_signal", "core_mechanism", "output_value"],
"mutation_delta_explanation": "Locks the non-contact cardiopulmonary input_signal and core_mechanism from Hop 1, but mutates governing_constraint to survive inside a 3-Tesla MRI bore via hollow dielectric waveguide coupling.",
"title": "MRI-Bore Dielectric-Waveguide Cardiac & Respiratory Gating Radar",
"updated_primitives": {
"input_signal": "24 GHz RF chirp guided down a hollow PTFE dielectric tube onto a patient's thorax inside an MRI bore.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat-frequency phase-shift extraction.",
"governing_constraint": "Zero ferromagnetic materials inside the 3-Tesla Faraday cage and immunity to kHz gradient coil switching pulses.",
"output_value": "Sub-millisecond mechanical apex-beat trigger to gate MRI slice acquisition without adhesive ECG electrodes."
},
"pillar_mutation_history": { "input_signal": 1, "core_mechanism": 0, "governing_constraint": 2, "output_value": 0 },
"concrete_application_scenario": "Cuts patient prep time by 6 minutes per cardiac MRI scan by eliminating chest shaving and expensive fiber-optic ECG leads.",
"friction_delta": {
"pain_severity_score": 9,
"technical_feasibility_score": 8,
"regulatory_or_adoption_barrier_reduction": 7,
"paradigm_novelty_score": 9,
"physics_or_logic_violation_check": "PASS: 24 GHz is far above the 128 MHz proton Larmor frequency; PTFE dielectric waveguide keeps all electronics outside the bore."
},
"composite_score": 8.29
},
"hop1_v2_hop2_1": {
"node_id": "hop1_v2_hop2_1",
"parent_id": "hop1_v2",
"parent_ids": ["hop1_v2"],
"hop_depth": 2,
"node_type": "divergent",
"applied_vector": "Structural / Topological Inversion",
"archetypal_move": "Symbiotic Parasite (Host Attachment)",
"mutated_pillar": "input_signal",
"locked_pillars": ["core_mechanism", "governing_constraint", "output_value"],
"mutation_delta_explanation": "Locks the near-field (<20mm) millimeter-wave phase-profiling constraint from hop1_v2, but inverts the topology: embeds a stationary linear array under a high-speed tensioned web roller while thin films move over it at 10 m/s.",
"title": "Inline Roll-to-Roll Thin-Film Calendering Thickness & Coat-Weight Gauge",
"updated_primitives": {
"input_signal": "Near-field millimeter-wave chirp coupling through high-speed moving polymer/coating webs on a steel calender roller.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat-frequency phase-shift extraction.",
"governing_constraint": "Near-field standoff (<15mm) and sub-micron phase stability across a 2-meter-wide industrial web.",
"output_value": "Real-time cross-web dielectric coat-weight and thickness profile to auto-adjust die slot actuators."
},
"pillar_mutation_history": { "input_signal": 2, "core_mechanism": 0, "governing_constraint": 1, "output_value": 0 },
"concrete_application_scenario": "Replaces hazardous radioactive Krypton-85 / Strontium-90 beta-gauges in paper, barrier-film, and adhesive coating mills.",
"friction_delta": {
"pain_severity_score": 9,
"technical_feasibility_score": 8,
"regulatory_or_adoption_barrier_reduction": 9,
"paradigm_novelty_score": 8,
"physics_or_logic_violation_check": "PASS: Differential phase shift between bare steel roller reflection and coated web reflection resolves 2-micron dielectric thickness."
},
"composite_score": 8.41
},
"hop1_v2_hop2_2": {
"node_id": "hop1_v2_hop2_2",
"parent_id": "hop1_v2",
"parent_ids": ["hop1_v2"],
"hop_depth": 2,
"node_type": "divergent",
"applied_vector": "Domain / Substrate Adjacency",
"archetypal_move": "Orthogonal Bridge (2-Node Recombination)",
"mutated_pillar": "output_value",
"locked_pillars": ["input_signal", "core_mechanism", "governing_constraint"],
"mutation_delta_explanation": "Locks the near-field sub-surface dielectric scanner from hop1_v2, but mutates output_value to map internal vascular cambium water stress and heartwood rot inside living orchard trees and timber.",
"title": "Non-Invasive Cambium Sap-Flow & Internal Heartwood Rot Tomographer",
"updated_primitives": {
"input_signal": "Near-field millimeter-wave chirp coupled through outer bark into xylem/cambium layers of standing timber.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat-frequency phase-shift extraction.",
"governing_constraint": "Near-field standoff (<20mm) and wet-bark dielectric attenuation depth limit.",
"output_value": "Sub-bark xylem hydration index and early fungal heartwood cavitation map without drilling core bores."
},
"pillar_mutation_history": { "input_signal": 0, "core_mechanism": 0, "governing_constraint": 1, "output_value": 2 },
"concrete_application_scenario": "Used by utility arborists inspecting wooden power poles and high-value almond/avocado orchards for drought stress.",
"friction_delta": {
"pain_severity_score": 7,
"technical_feasibility_score": 8,
"regulatory_or_adoption_barrier_reduction": 9,
"paradigm_novelty_score": 8,
"physics_or_logic_violation_check": "PASS: Sap permittivity contrast against fungal void cavities produces distinct phase reflection delay."
},
"composite_score": 7.96
},
"hop1_v5_hop2_1": {
"node_id": "hop1_v5_hop2_1",
"parent_id": "hop1_v5",
"parent_ids": ["hop1_v5"],
"hop_depth": 2,
"node_type": "divergent",
"applied_vector": "Byproduct / Exhaust Adjacency",
"archetypal_move": "Passive / Active Energy Flip",
"mutated_pillar": "output_value",
"locked_pillars": ["input_signal", "core_mechanism", "governing_constraint"],
"mutation_delta_explanation": "Locks the zero-power passive SAW/metamaterial tag constraint from hop1_v5, but mutates output_value: instead of static obstacle ID, harvests thermal/mechanical lattice expansion of the tag substrate to read remote temperature and pressure.",
"title": "Battery-Free Rotary Kiln & Turbine Blade Wireless Thermal-Phase Telemetry",
"updated_primitives": {
"input_signal": "24 GHz electromagnetic sweep illuminating passive piezoelectric/metamaterial tags inside rotating machinery.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat-frequency phase-shift extraction of passive delay echoes.",
"governing_constraint": "Zero onboard battery/silicon (survives 350C and 10,000-G centrifugal acceleration where batteries explode).",
"output_value": "Continuous wireless rotor temperature and acoustic stress telemetry extracted from thermally induced phase delay."
},
"pillar_mutation_history": { "input_signal": 0, "core_mechanism": 0, "governing_constraint": 1, "output_value": 2 },
"concrete_application_scenario": "Bonded directly onto high-speed EV motor rotors, autoclaves, and gas-turbine compressor stages.",
"friction_delta": {
"pain_severity_score": 9,
"technical_feasibility_score": 8,
"regulatory_or_adoption_barrier_reduction": 8,
"paradigm_novelty_score": 9,
"physics_or_logic_violation_check": "PASS: Langasite/LiNbO3 SAW substrates exhibit linear temperature coefficient of delay (TCD), shifting echo phase predictably."
},
"composite_score": 8.48
},
"hop1_v6_hop2_1": {
"node_id": "hop1_v6_hop2_1",
"parent_id": "hop1_v6",
"parent_ids": ["hop1_v6"],
"hop_depth": 2,
"node_type": "divergent",
"applied_vector": "Scale / Resolution Adjacency",
"archetypal_move": "Passive / Active Energy Flip",
"mutated_pillar": "output_value",
"locked_pillars": ["input_signal", "core_mechanism", "governing_constraint"],
"mutation_delta_explanation": "Locks the stationary industrial sensor topology and harsh dust/weather constraint from hop1_v6, but scales velocity sensitivity down by 4 orders of magnitude to measure sub-millimeter structural harmonic sway and foundation creep.",
"title": "Sub-Millimeter Structural Resonance & Bridge Foundation Creep Interferometer",
"updated_primitives": {
"input_signal": "24 GHz FMCW chirp illuminating load-bearing civil columns, tension cables, or retaining walls through dust/fog.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat-frequency phase-shift extraction.",
"governing_constraint": "Opaque dust, rain/fog, and continuous outdoor industrial vibration.",
"output_value": "Sub-100-micron structural harmonic frequency shift and slow foundation settling creep vector before fatigue failure."
},
"pillar_mutation_history": { "input_signal": 1, "core_mechanism": 0, "governing_constraint": 0, "output_value": 2 },
"concrete_application_scenario": "Permanent non-contact interferometer monitoring dam faces, mine tailings walls, and bridge stay-cables in zero-visibility weather.",
"friction_delta": {
"pain_severity_score": 8,
"technical_feasibility_score": 9,
"regulatory_or_adoption_barrier_reduction": 9,
"paradigm_novelty_score": 8,
"physics_or_logic_violation_check": "PASS: Differential interferometric phase tracking at 24 GHz resolves 50-micron displacement against a fixed reference corner reflector."
},
"composite_score": 8.53
},
/* ==================== GENERATION 3: DIVERGENT NODES (3/4 MUTATED, SACRED ANCHOR LOCKED) ==================== */
"hop3_div_1": {
"node_id": "hop3_div_1",
"parent_id": "hop1_v1_hop2_1",
"parent_ids": ["hop1_v1_hop2_1"],
"hop_depth": 3,
"node_type": "divergent",
"applied_vector": "Constraint / Environment Adjacency",
"archetypal_move": "Orthogonal Bridge (2-Node Recombination)",
"mutated_pillar": "governing_constraint",
"locked_pillars": ["input_signal", "core_mechanism", "output_value"],
"mutation_delta_explanation": "3rd-Generation Hop: Mutates governing_constraint from indoor drywall HVAC rooms to subterranean agricultural root-zones, using buried leaky-wave coaxial waveguides to track root respiration & soil water table cavitation.",
"title": "Subterranean Root-Zone Dielectric Moisture & Mycorrhizal Respiration Tomographer",
"updated_primitives": {
"input_signal": "Sub-surface RF chirp penetrating soil strata and reflecting off root-zone water films and gas micro-voids.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat-frequency phase-shift extraction. [SACRED ANCHOR]",
"governing_constraint": "High-loss wet clay soil attenuation and buried plow-depth survival (zero above-ground masts).",
"output_value": "3D volumetric soil moisture horizon + root-zone gas exchange rate to trigger precision sub-surface drip fertigation."
},
"pillar_mutation_history": { "input_signal": 1, "core_mechanism": 0, "governing_constraint": 3, "output_value": 2 },
"concrete_application_scenario": "Buried permanently below plow depth in high-value vineyards and orchards to automate deficit irrigation with zero surface hardware.",
"friction_delta": {
"pain_severity_score": 8,
"technical_feasibility_score": 7,
"regulatory_or_adoption_barrier_reduction": 9,
"paradigm_novelty_score": 9,
"physics_or_logic_violation_check": "PASS: Slotted leaky-wave coax buried along drip lines confines path length to <40cm, overcoming soil skin-depth attenuation."
},
"composite_score": 8.28
},
"hop3_div_2": {
"node_id": "hop3_div_2",
"parent_id": "hop1_v2_hop2_1",
"parent_ids": ["hop1_v2_hop2_1"],
"hop_depth": 3,
"node_type": "divergent",
"applied_vector": "Byproduct / Exhaust Adjacency",
"archetypal_move": "Pickaxe Extraction (Internal Scaffolding)",
"mutated_pillar": "output_value",
"locked_pillars": ["input_signal", "core_mechanism", "governing_constraint"],
"mutation_delta_explanation": "3rd-Generation Hop: Mutates output_value on the roll-to-roll near-field scanner from simple thickness gauging to extracting cross-polarization phase depolarization noise to catch lithium dendrite precursors and dry-electrolyte micro-voids.",
"title": "Gigafactory Solid-State Battery Electrolyte Micro-Void & Dendrite Interferometer",
"updated_primitives": {
"input_signal": "Near-field millimeter-wave chirp coupling through high-speed moving solid-state ceramic/polymer battery separator webs.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat-frequency phase-shift extraction. [SACRED ANCHOR]",
"governing_constraint": "Near-field standoff (<10mm) inside an anhydrous dry-room at 60 meters/minute web speed.",
"output_value": "Real-time sub-surface electrolyte porosity defect map & automated laser web-splicer excision trigger before cell winding."
},
"pillar_mutation_history": { "input_signal": 2, "core_mechanism": 0, "governing_constraint": 1, "output_value": 3 },
"concrete_application_scenario": "Prevents catastrophic solid-state EV battery short-circuits by catching 10-micron electrolyte voids inline without X-ray radiation.",
"friction_delta": {
"pain_severity_score": 10,
"technical_feasibility_score": 8,
"regulatory_or_adoption_barrier_reduction": 9,
"paradigm_novelty_score": 10,
"physics_or_logic_violation_check": "PASS: Non-ionizing mmWave replaces lead-shielded X-ray gauges while resolving local permittivity drops caused by air inclusions."
},
"composite_score": 9.31
},
"hop3_div_3": {
"node_id": "hop3_div_3",
"parent_id": "hop1_v6_hop2_1",
"parent_ids": ["hop1_v6_hop2_1"],
"hop_depth": 3,
"node_type": "divergent",
"applied_vector": "Constraint / Environment Adjacency",
"archetypal_move": "Passive / Active Energy Flip",
"mutated_pillar": "governing_constraint",
"locked_pillars": ["input_signal", "core_mechanism", "output_value"],
"mutation_delta_explanation": "3rd-Generation Hop: Mutates governing_constraint on the structural interferometer by etching a passive sub-wavelength RF metamaterial spiral directly into nuclear/chemical pressure vessel flange bolts for zero-power tamper & creep auditing.",
"title": "Acoustic-RF Metamaterial Tamper-Evident Nuclear Containment Fastener Seal",
"updated_primitives": {
"input_signal": "24 GHz FMCW sweep illuminating passive metamaterial-etched structural bolts on high-radiation containment vessels.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat-frequency phase-shift extraction. [SACRED ANCHOR]",
"governing_constraint": "Zero electronics/batteries under extreme gamma radiation and 40-year unmaintained storage life.",
"output_value": "Cryptographic mechanical torque-relaxation & sub-micron tamper phase signature read from 10 meters away."
},
"pillar_mutation_history": { "input_signal": 1, "core_mechanism": 0, "governing_constraint": 3, "output_value": 2 },
"concrete_application_scenario": "IAEA safeguard inspection and petrochemical flange monitoring where active strain gauges fail from radiation or battery decay.",
"friction_delta": {
"pain_severity_score": 8,
"technical_feasibility_score": 8,
"regulatory_or_adoption_barrier_reduction": 8,
"paradigm_novelty_score": 9,
"physics_or_logic_violation_check": "PASS: Split-ring resonator (SRR) gap capacitance shifts linearly with axial bolt elongation, altering reflected FMCW phase."
},
"composite_score": 8.40
},
/* ==================== GENERATION 3: CONVERGENT NODES (2-PARENT TRIZ BREEDING) ==================== */
"hop3_conv_1": {
"node_id": "hop3_conv_1",
"parent_id": "hop1_v2_hop2_1",
"parent_ids": ["hop1_v2_hop2_1", "hop1_v5_hop2_1"],
"hop_depth": 3,
"node_type": "convergent",
"applied_vector": "TRIZ Cross-Branch Convergence",
"archetypal_move": "Orthogonal Bridge (2-Node Recombination)",
"mutated_pillar": "output_value",
"locked_pillars": ["input_signal", "core_mechanism", "governing_constraint"],
"mutation_delta_explanation": "CONVERGENT GEN-3 BREEDING: Fuses Branch A (hop1_v2_hop2_1: Near-field micron-resolution phase profiling) with Branch B (hop1_v5_hop2_1: Zero-power passive wireless SAW/metamaterial backscatter) to create unpowered sub-micron strain patches read at high speed.",
"title": "Chipless Sub-Wavelength Metamaterial Structural Torque & Micro-Strain Patch",
"convergence_synthesis": {
"parent_a_id": "hop1_v2_hop2_1",
"parent_a_contribution": "Near-field sub-micron differential phase interferometry across moving/rotating surfaces.",
"parent_b_id": "hop1_v5_hop2_1",
"parent_b_contribution": "Battery-free passive harmonic backscatter surviving 10,000-G centrifugal force and 350C heat.",
"triz_contradiction_resolved": "High-resolution strain/torque sensing requires active wheatstone bridges + slip rings/batteries (which fail on high-RPM shafts), while passive RFID tags lack micron strain resolution. Etching a high-Q dielectric metamaterial grating onto the shaft resolves both."
},
"updated_primitives": {
"input_signal": "Near-field millimeter-wave chirp illuminating a chipless metamaterial grating printed on a spinning drivetrain shaft.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat-frequency phase-shift extraction. [SACRED ANCHOR]",
"governing_constraint": "Zero onboard power/silicon on 20,000-RPM spinning shafts with <10mm stator reader clearance.",
"output_value": "Real-time dynamic shaft torque, torsional flutter, and micro-fatigue crack vector without slip-rings."
},
"pillar_mutation_history": { "input_signal": 2, "core_mechanism": 0, "governing_constraint": 1, "output_value": 3 },
"concrete_application_scenario": "Direct inline torque sensor for electric aircraft propulsors, wind turbine gearboxes, and Formula-1/EV drivetrains.",
"friction_delta": {
"pain_severity_score": 10,
"technical_feasibility_score": 8,
"regulatory_or_adoption_barrier_reduction": 9,
"paradigm_novelty_score": 10,
"physics_or_logic_violation_check": "PASS: Torsional shear deforms the printed conjugate split-ring grating pitch by microns, producing a strong differential phase shift between orthogonal polarizations."
},
"composite_score": 9.31
},
"hop3_conv_2": {
"node_id": "hop3_conv_2",
"parent_id": "hop1_v1_hop2_2",
"parent_ids": ["hop1_v1_hop2_2", "hop1_v6_hop2_1"],
"hop_depth": 3,
"node_type": "convergent",
"applied_vector": "TRIZ Cross-Branch Convergence",
"archetypal_move": "Symbiotic Parasite (Host Attachment)",
"mutated_pillar": "output_value",
"locked_pillars": ["input_signal", "core_mechanism", "governing_constraint"],
"mutation_delta_explanation": "CONVERGENT GEN-3 BREEDING: Fuses Branch A (hop1_v1_hop2_2: Dielectric-coupled micro-Doppler cardiac/respiration detection) with Branch B (hop1_v6_hop2_1: Sub-millimeter structural creep & collapse interferometry) into a dual-mode earthquake rubble rescue system.",
"title": "Seismic Rubble-Penetrating Vital-Sign & Secondary Void-Collapse Triangulator",
"convergence_synthesis": {
"parent_a_id": "hop1_v1_hop2_2",
"parent_a_contribution": "Sub-millimeter human cardiopulmonary phase extraction through dense dielectric barriers.",
"parent_b_id": "hop1_v6_hop2_1",
"parent_b_contribution": "Sub-100-micron structural settling and harmonic creep interferometry of unstable masonry/concrete.",
"triz_contradiction_resolved": "In collapsed buildings, shifting rubble creates background phase clutter that masks weak survivor breathing signals, while rescuers risk fatal secondary collapse. Using the structural creep channel as an active phase-cancellation reference simultaneously unmasks survivor vitals AND warns rescuers 60s before rubble shifts."
},
"updated_primitives": {
"input_signal": "Multi-static millimeter/sub-GHz stepped-FMCW sweep penetrating collapsed reinforced concrete and void spaces.",
"core_mechanism": "Homodyne quadrature mixing + 2D Range-Doppler FFT beat-frequency phase-shift extraction. [SACRED ANCHOR]",
"governing_constraint": "Unstable shifting rubble clutter, zero line-of-sight, and battery-powered field deployment.",
"output_value": "Simultaneous 3D survivor heartbeat/respiration localization + real-time structural void-collapse warning alarm for rescue crews."
},
"pillar_mutation_history": { "input_signal": 1, "core_mechanism": 0, "governing_constraint": 2, "output_value": 3 },
"concrete_application_scenario": "Deployed by FEMA Urban Search and Rescue (USAR) teams on earthquake rubble piles to locate trapped survivors while protecting rescuers from secondary collapse.",
"friction_delta": {
"pain_severity_score": 10,
"technical_feasibility_score": 8,
"regulatory_or_adoption_barrier_reduction": 8,
"paradigm_novelty_score": 10,
"physics_or_logic_violation_check": "PASS: Structural creep occurs as a slow monotonic phase ramp (<0.05 Hz) across all range bins, whereas respiration is localized and periodic (0.2-0.4 Hz), allowing clean subspace separation."
},
"composite_score": 9.16
}
},
"edges": [
/* Gen 0 -> Gen 1 */
{ "source": "root_0", "target": "hop1_v1", "vector": "Domain / Substrate Adjacency", "mutated_pillar": "input_signal" },
{ "source": "root_0", "target": "hop1_v2", "vector": "Scale / Resolution Adjacency", "mutated_pillar": "governing_constraint" },
{ "source": "root_0", "target": "hop1_v3", "vector": "Temporal / Workflow Adjacency", "mutated_pillar": "output_value" },
{ "source": "root_0", "target": "hop1_v4", "vector": "Byproduct / Exhaust Adjacency", "mutated_pillar": "output_value" },
{ "source": "root_0", "target": "hop1_v5", "vector": "Constraint / Environment Adjacency", "mutated_pillar": "governing_constraint" },
{ "source": "root_0", "target": "hop1_v6", "vector": "Structural / Topological Inversion", "mutated_pillar": "input_signal" },
/* Gen 1 -> Gen 2 */
{ "source": "hop1_v1", "target": "hop1_v1_hop2_1", "vector": "Byproduct / Exhaust Adjacency", "mutated_pillar": "output_value" },
{ "source": "hop1_v1", "target": "hop1_v1_hop2_2", "vector": "Constraint / Environment Adjacency", "mutated_pillar": "governing_constraint" },
{ "source": "hop1_v2", "target": "hop1_v2_hop2_1", "vector": "Structural / Topological Inversion", "mutated_pillar": "input_signal" },
{ "source": "hop1_v2", "target": "hop1_v2_hop2_2", "vector": "Domain / Substrate Adjacency", "mutated_pillar": "output_value" },
{ "source": "hop1_v5", "target": "hop1_v5_hop2_1", "vector": "Byproduct / Exhaust Adjacency", "mutated_pillar": "output_value" },
{ "source": "hop1_v6", "target": "hop1_v6_hop2_1", "vector": "Scale / Resolution Adjacency", "mutated_pillar": "output_value" },
/* Gen 2 -> Gen 3 Divergent (Single Parent) */
{ "source": "hop1_v1_hop2_1", "target": "hop3_div_1", "vector": "Constraint / Environment Adjacency", "mutated_pillar": "governing_constraint" },
{ "source": "hop1_v2_hop2_1", "target": "hop3_div_2", "vector": "Byproduct / Exhaust Adjacency", "mutated_pillar": "output_value" },
{ "source": "hop1_v6_hop2_1", "target": "hop3_div_3", "vector": "Constraint / Environment Adjacency", "mutated_pillar": "governing_constraint" },
/* Gen 2 -> Gen 3 Convergent (Dual Parent TRIZ Breeding) */
{ "source": "hop1_v2_hop2_1", "target": "hop3_conv_1", "vector": "TRIZ Cross-Branch Convergence", "mutated_pillar": "output_value", "is_convergent": true },
{ "source": "hop1_v5_hop2_1", "target": "hop3_conv_1", "vector": "TRIZ Cross-Branch Convergence", "mutated_pillar": "output_value", "is_convergent": true },
{ "source": "hop1_v1_hop2_2", "target": "hop3_conv_2", "vector": "TRIZ Cross-Branch Convergence", "mutated_pillar": "output_value", "is_convergent": true },
{ "source": "hop1_v6_hop2_1", "target": "hop3_conv_2", "vector": "TRIZ Cross-Branch Convergence", "mutated_pillar": "output_value", "is_convergent": true }
]
};
/********************************************************************
* 2. COLOR PALETTES & VECTOR DEFINITIONS
********************************************************************/
const VECTOR_PALETTE = {
"Domain / Substrate Adjacency": { bg: "#0284c7", border: "#38bdf8", text: "#e0f2fe", short: "Domain/Substrate" },
"Scale / Resolution Adjacency": { bg: "#7c3aed", border: "#a78bfa", text: "#ede9fe", short: "Scale/Resolution" },
"Temporal / Workflow Adjacency": { bg: "#d97706", border: "#fbbf24", text: "#fef3c7", short: "Temporal/Workflow" },
"Byproduct / Exhaust Adjacency": { bg: "#059669", border: "#34d399", text: "#d1fae5", short: "Byproduct/Exhaust" },
"Constraint / Environment Adjacency":{ bg: "#e11d48", border: "#fb7185", text: "#ffe4e6", short: "Constraint/Env" },
"Structural / Topological Inversion":{ bg: "#4f46e5", border: "#818cf8", text: "#e0e7ff", short: "Structural Flip" },
"TRIZ Cross-Branch Convergence": { bg: "#86198f", border: "#f472b6", text: "#fae8ff", short: "TRIZ Convergent (2-Parent)" }
};
const PILLAR_LABELS = {
"input_signal": "Input Signal / Substrate",
"core_mechanism": "Core Mechanism (Sacred Anchor)",
"governing_constraint": "Governing Constraint",
"output_value": "Output Value / Action"
};
// Global Application State
let rawDagData = null;
let visNetwork = null;
let visNodesDataSet = new vis.DataSet();
let visEdgesDataSet = new vis.DataSet();
let currentColorMode = 'hop'; // 'hop' | 'viability' | 'vector'
let currentLayoutMode = 'LR'; // 'LR' | 'UD' | 'FORCE'
let selectedNodeId = 'hop3_conv_1'; // Start on a Gen 3 Convergent node so the user sees the full Gen 0->3 trace immediately
let lineageSpotlightEnabled = true;
/********************************************************************
* 3. INITIALIZATION & NETWORK SETUP
********************************************************************/
window.addEventListener('DOMContentLoaded', () => {
lucide.createIcons();
setupDragAndDrop();
loadDemoDataset();
});
function loadDemoDataset() {
rawDagData = JSON.parse(JSON.stringify(DEMO_DAG_DATA));
normalizeAndValidateDAG(rawDagData);
document.getElementById('datasetTitleDisplay').textContent =
`Loaded: ${rawDagData.nodes['root_0']?.title || 'Adjacency DAG'} (${Object.keys(rawDagData.nodes).length} Nodes, Gen 0→3)`;
populateGen3QuickJump();
renderVisGraph();
selectNode('hop3_conv_1');
showToast("Loaded 18-Node Multi-Gen DAG (Gen 0 → Gen 3 Divergent & TRIZ Convergent)");
}
/**
* Computes generation_adjusted_score, normalizes parent_ids for convergent nodes,
* reconstructs pillar_mutation_history if missing, and checks Sacred Anchor & Tabu rules.
*/
function normalizeAndValidateDAG(dag) {
let orthoViolations = 0;
Object.values(dag.nodes).forEach(node => {
const isRoot = !node.hop_depth || node.hop_depth === 0 || node.node_id === 'root_0';
if (isRoot) {
node.hop_depth = 0;
node.parent_ids = [];
node.node_type = 'root';
} else {
// Ensure parent_ids array is populated
if (!Array.isArray(node.parent_ids)) {
node.parent_ids = node.parent_id ? [node.parent_id] : [];
}
if (!node.parent_id && node.parent_ids.length > 0) {
node.parent_id = node.parent_ids[0];
}
if (!node.node_type) {
node.node_type = node.parent_ids.length > 1 ? 'convergent' : 'divergent';
}
// Compute Generation-Adjusted Emergence Score
if (node.friction_delta) {
const fd = node.friction_delta;
const pain = fd.pain_severity_score || 7;
const feas = fd.technical_feasibility_score || 7;
const barr = fd.regulatory_or_adoption_barrier_reduction || 7;
const nov = fd.paradigm_novelty_score || (node.hop_depth === 3 ? 9 : (node.hop_depth === 2 ? 8 : 6));
fd.paradigm_novelty_score = nov;
const baseViability = (pain * 0.30) + (feas * 0.45) + (barr * 0.25);
if (node.hop_depth === 1) {
node.composite_score = Number(baseViability.toFixed(2));
} else if (node.hop_depth === 2) {
node.composite_score = Number(((baseViability * 0.75) + (nov * 0.25)).toFixed(2));
} else {
const feasGate = feas >= 6 ? 1.0 : 0.65;
node.composite_score = Number((((baseViability * 0.60) + (nov * 0.40)) * feasGate).toFixed(2));
}
}
// Verify Sacred Anchor (core_mechanism must never be mutated in Gen 1..3)
if (node.mutated_pillar === 'core_mechanism') {
orthoViolations++;
node._orthoWarning = true;
}
}
});
const badge = document.getElementById('orthogonalityBadge');
if (orthoViolations === 0) {
badge.className = "px-2 py-0.5 rounded bg-emerald-950/60 border border-emerald-700/50 text-emerald-300 flex items-center gap-1";
badge.innerHTML = `<i data-lucide="shield-check" class="w-3.5 h-3.5"></i><span>Sacred Anchor & Tabu Valid</span>`;
} else {
badge.className = "px-2 py-0.5 rounded bg-rose-950/70 border border-rose-600/50 text-rose-300 flex items-center gap-1";
badge.innerHTML = `<i data-lucide="alert-triangle" class="w-3.5 h-3.5"></i><span>${orthoViolations} Anchor Violation(s)</span>`;
}
lucide.createIcons();
}
function populateGen3QuickJump() {
const container = document.getElementById('gen3QuickJumpContainer');
if (!container || !rawDagData) return;
container.innerHTML = '';
const gen3Nodes = Object.values(rawDagData.nodes).filter(n => n.hop_depth === 3);
gen3Nodes.forEach(node => {
const isConv = node.node_type === 'convergent' || (node.parent_ids && node.parent_ids.length > 1);
const btn = document.createElement('button');
btn.onclick = () => {
selectNode(node.node_id);
focusLineageSubgraph();
};
btn.className = isConv
? 'px-2 py-0.5 rounded text-[10px] font-mono font-semibold bg-fuchsia-950/90 hover:bg-fuchsia-800 text-fuchsia-200 border border-fuchsia-500/50 transition shrink-0 flex items-center gap-1'
: 'px-2 py-0.5 rounded text-[10px] font-mono font-medium bg-amber-950/80 hover:bg-amber-800/80 text-amber-200 border border-amber-500/40 transition shrink-0';
btn.innerHTML = isConv
? `<i data-lucide="git-merge" class="w-2.5 h-2.5 text-fuchsia-300"></i>${node.node_id} (Bred)`
: `${node.node_id}`;
container.appendChild(btn);
});
lucide.createIcons();
}
/********************************************************************
* 4. LINEAGE PATH COMPUTATION (ANCESTORS + DESCENDANTS)
********************************************************************/
function computeActiveLineageSet(targetId) {
const activeNodes = new Set();
const activeEdgePairs = new Set();
if (!rawDagData || !rawDagData.nodes[targetId]) return { activeNodes, activeEdgePairs };
// 1. Walk upstream (BFS/DFS across all parent_ids up to root_0)
const upQueue = [targetId];
while (upQueue.length > 0) {
const currId = upQueue.shift();
if (activeNodes.has(currId)) continue;
activeNodes.add(currId);
const currNode = rawDagData.nodes[currId];
if (!currNode) continue;
const parents = currNode.parent_ids || (currNode.parent_id ? [currNode.parent_id] : []);
parents.forEach(pId => {
if (rawDagData.nodes[pId]) {
activeEdgePairs.add(`${pId}->${currId}`);
upQueue.push(pId);
}
});
}
// 2. Also include direct 1-hop downstream children so user sees immediate forward options
Object.values(rawDagData.nodes).forEach(n => {
const parents = n.parent_ids || (n.parent_id ? [n.parent_id] : []);
if (parents.includes(targetId)) {
activeNodes.add(n.node_id);
activeEdgePairs.add(`${targetId}->${n.node_id}`);
}
});
return { activeNodes, activeEdgePairs };
}
function toggleLineageSpotlight() {
lineageSpotlightEnabled = !lineageSpotlightEnabled;
const btn = document.getElementById('traceToggleBtn');
const txt = document.getElementById('traceToggleText');
if (lineageSpotlightEnabled) {
btn.className = "px-3 py-1.5 rounded-lg bg-amber-500/20 hover:bg-amber-500/30 border border-amber-500/50 text-amber-300 text-xs font-semibold flex items-center gap-1.5 transition shadow";
txt.textContent = "Lineage Spotlight: ON";
} else {
btn.className = "px-3 py-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-slate-400 text-xs font-medium flex items-center gap-1.5 transition";
txt.textContent = "Lineage Spotlight: OFF";
}
renderVisGraph();
}
function focusLineageSubgraph() {
if (!visNetwork || !selectedNodeId) return;
const { activeNodes } = computeActiveLineageSet(selectedNodeId);
const nodeArray = Array.from(activeNodes).filter(id => visNodesDataSet.get(id));
if (nodeArray.length > 0) {
visNetwork.fit({
nodes: nodeArray,
animation: { duration: 450, easingFunction: 'easeInOutCubic' }
});
}
}
/********************************************************************
* 5. NODE & EDGE STYLING ENGINE (GEN 0 -> GEN 3 + CONVERGENCE)
********************************************************************/
function getNodeColors(node, isDimmed) {
if (isDimmed) {
return {
background: '#0f172a',
border: '#1e293b',
fontColor: '#475569',
highlightBg: '#1e293b',
highlightBorder: '#334155'
};
}
if (node.hop_depth === 0) {
return {
background: '#312e81',
border: '#818cf8',
fontColor: '#ffffff',
highlightBg: '#3730a3',
highlightBorder: '#c7d2fe'
};
}
const isConvergent = node.node_type === 'convergent' || (node.parent_ids && node.parent_ids.length > 1);
const score = node.composite_score || 0;
if (currentColorMode === 'hop') {
if (node.hop_depth === 1) {
return {
background: '#0c4a6e',
border: '#38bdf8',
fontColor: '#e0f2fe',
highlightBg: '#0369a1',
highlightBorder: '#7dd3fc'
};
} else if (node.hop_depth === 2) {
return {
background: '#3b0764',
border: '#c084fc',
fontColor: '#f3e8ff',
highlightBg: '#581c87',
highlightBorder: '#e9d5ff'
};
} else {
// Generation 3: Distinct styling for Convergent (2-parent bred) vs Divergent
if (isConvergent) {
return {
background: '#701a75',
border: '#f472b6',
fontColor: '#fdf4ff',
highlightBg: '#86198f',
highlightBorder: '#34d399'
};
} else {
return {
background: '#78350f',
border: '#fbbf24',
fontColor: '#fffbeb',
highlightBg: '#92400e',
highlightBorder: '#fde68a'
};
}
}
}
if (currentColorMode === 'viability') {
if (score >= 8.8) {
return { background: '#064e3b', border: '#34d399', fontColor: '#ecfdf5', highlightBg: '#047857', highlightBorder: '#6ee7b7' };
} else if (score >= 8.0) {
return { background: '#0c4a6e', border: '#38bdf8', fontColor: '#f0f9ff', highlightBg: '#0369a1', highlightBorder: '#7dd3fc' };
} else if (score >= 7.0) {
return { background: '#78350f', border: '#f59e0b', fontColor: '#fffbeb', highlightBg: '#92400e', highlightBorder: '#fbbf24' };
} else {
return { background: '#7f1d1d', border: '#ef4444', fontColor: '#fef2f2', highlightBg: '#991b1b', highlightBorder: '#f87171' };
}
}
if (currentColorMode === 'vector') {
const pal = VECTOR_PALETTE[node.applied_vector] || { bg: '#334155', border: '#94a3b8', text: '#f8fafc' };
return {
background: pal.bg,
border: pal.border,
fontColor: pal.text,
highlightBg: pal.bg,
highlightBorder: '#ffffff'
};
}
}
function wrapLabelText(str, maxCharsPerLine = 25) {
if (!str) return '';
const words = str.split(' ');
const lines = [];
let currentLine = '';
words.forEach(word => {
if ((currentLine + ' ' + word).trim().length > maxCharsPerLine) {
if (currentLine) lines.push(currentLine.trim());
currentLine = word;
} else {
currentLine += ' ' + word;
}
});
if (currentLine) lines.push(currentLine.trim());
return lines.slice(0, 3).join('\n');
}
/********************************************************************
* 6. BUILD & RENDER VIS.JS NETWORK
********************************************************************/
function renderVisGraph() {
if (!rawDagData || !rawDagData.nodes) return;
const minScore = parseFloat(document.getElementById('minScoreSlider').value);
const hidePruned = document.getElementById('hidePrunedCheckbox').checked;
const vectorFilter = document.getElementById('vectorFilterSelect').value;
const { activeNodes, activeEdgePairs } = computeActiveLineageSet(selectedNodeId);
const visNodes = [];
const visEdges = [];
let totalCount = 0;
let convergentCount = 0;
const visibleNodeIds = new Set();
Object.values(rawDagData.nodes).forEach(node => {
totalCount++;
const isRoot = node.hop_depth === 0;
const isConvergent = node.node_type === 'convergent' || (node.parent_ids && node.parent_ids.length > 1);
if (isConvergent) convergentCount++;
const score = node.composite_score || 0;
const passesScore = isRoot || score >= minScore;
const passesVector = isRoot || vectorFilter === 'ALL' || node.applied_vector === vectorFilter;
const matchesFilter = passesScore && passesVector;
if (hidePruned && !matchesFilter) return;
visibleNodeIds.add(node.node_id);
// Node is dimmed if it fails filter OR if Lineage Spotlight is active and node is outside active lineage
const isOutsideLineage = lineageSpotlightEnabled && selectedNodeId && !activeNodes.has(node.node_id);
const isDimmed = !matchesFilter || isOutsideLineage;
const isSelected = node.node_id === selectedNodeId;
const isInActiveLineage = activeNodes.has(node.node_id);
const palette = getNodeColors(node, isDimmed);
const wrappedTitle = wrapLabelText(node.title, 25);
let headerTag = '';
if (isRoot) {
headerTag = `GEN 0 • ROOT ANCHOR`;
} else if (isConvergent) {
headerTag = `GEN 3 CONVERGENT (2-PARENT) • ★ ${score.toFixed(2)}`;
} else {
headerTag = `GEN ${node.hop_depth} (${node.hop_depth}/4 Mutated) • ★ ${score.toFixed(2)}`;
}
const vecShort = VECTOR_PALETTE[node.applied_vector]?.short || node.applied_vector || '';
const label = isRoot
? `${headerTag}\n${wrappedTitle}\n[Anchor: core_mechanism]`
: `${headerTag}\n${wrappedTitle}\n[${vecShort}]`;
visNodes.push({
id: node.node_id,
label: label,
level: node.hop_depth,
shape: 'box',
margin: { top: 10, right: 13, bottom: 10, left: 13 },
borderWidth: isSelected ? 4 : (isInActiveLineage && lineageSpotlightEnabled ? 3 : 2),
borderWidthSelected: 4,
shapeProperties: {
borderDashes: isConvergent && !isDimmed ? [6, 3] : false,
borderRadius: isRoot ? 10 : 8
},
color: {
background: palette.background,
border: isSelected ? '#fbbf24' : palette.border,
highlight: {
background: palette.highlightBg,
border: '#fbbf24'
},
hover: {
background: palette.highlightBg,
border: palette.highlightBorder
}
},
font: {
color: palette.fontColor,
face: 'Inter, sans-serif',
size: isRoot ? 13 : 11.5,
align: 'left'
},
shadow: {
enabled: !isDimmed,
color: isSelected
? 'rgba(251, 191, 36, 0.55)'
: (isConvergent ? 'rgba(244, 114, 182, 0.45)' : 'rgba(0,0,0,0.6)'),
size: isSelected ? 22 : 12,
x: 0,
y: 4
}
});
});
// Build Edges
(rawDagData.edges || []).forEach((edge, idx) => {
if (!visibleNodeIds.has(edge.source) || !visibleNodeIds.has(edge.target)) return;
const pairKey = `${edge.source}->${edge.target}`;
const isLineageEdge = activeEdgePairs.has(pairKey);
const targetNode = rawDagData.nodes[edge.target];
const score = targetNode?.composite_score || 0;
const isFilterDimmed =
(score < minScore) ||
(vectorFilter !== 'ALL' && targetNode?.applied_vector !== vectorFilter);
const isEdgeDimmed = isFilterDimmed || (lineageSpotlightEnabled && !isLineageEdge);
let edgeColor = '#64748b';
if (isEdgeDimmed) {
edgeColor = '#1e293b';
} else if (edge.is_convergent) {
edgeColor = '#f472b6'; // Bright magenta for convergent TRIZ breeding edges
} else if (lineageSpotlightEnabled && isLineageEdge) {
edgeColor = '#38bdf8'; // Glowing sky-cyan for active lineage path
} else if (currentColorMode === 'vector' && VECTOR_PALETTE[edge.vector]) {
edgeColor = VECTOR_PALETTE[edge.vector].border;
}
visEdges.push({
id: `e_${idx}`,
from: edge.source,
to: edge.target,
label: isEdgeDimmed ? '' : (edge.is_convergent ? `⚡ TRIZ + Δ ${edge.mutated_pillar}` : `Δ ${edge.mutated_pillar}`),
font: {
color: edge.is_convergent ? '#f472b6' : (isLineageEdge ? '#e0f2fe' : '#94a3b8'),
size: 10,
face: 'JetBrains Mono, monospace',
background: '#090e17',
strokeWidth: 0
},
arrows: {
to: { enabled: true, scaleFactor: isLineageEdge ? 0.85 : 0.65 }
},
color: {
color: edgeColor,
highlight: '#fbbf24',
hover: '#38bdf8'
},
width: isEdgeDimmed ? 1 : (isLineageEdge ? 3.2 : 1.8),
dashes: edge.is_convergent ? [6, 4] : (isEdgeDimmed ? [4, 4] : false),
smooth: {
type: currentLayoutMode === 'FORCE' ? 'dynamic' : 'cubicBezier',
forceDirection: currentLayoutMode === 'LR' ? 'horizontal' : (currentLayoutMode === 'UD' ? 'vertical' : 'none'),
roundness: 0.42
}
});
});
document.getElementById('statTotalNodes').textContent = totalCount;
document.getElementById('statConvergentNodes').textContent = convergentCount;
visNodesDataSet.clear();
visEdgesDataSet.clear();
visNodesDataSet.add(visNodes);
visEdgesDataSet.add(visEdges);
const container = document.getElementById('visNetworkContainer');
const options = getVisLayoutOptions();
if (!visNetwork) {
visNetwork = new vis.Network(container, { nodes: visNodesDataSet, edges: visEdgesDataSet }, options);
visNetwork.on('click', (params) => {
if (params.nodes && params.nodes.length > 0) {
selectNode(params.nodes[0]);
}
});
} else {
visNetwork.setOptions(options);
}
updateLegend();
}
function getVisLayoutOptions() {
const isHierarchical = currentLayoutMode === 'LR' || currentLayoutMode === 'UD';
return {
interaction: {
hover: true,
tooltipDelay: 150,
navigationButtons: false,
keyboard: false
},
layout: isHierarchical
? {
hierarchical: {
enabled: true,
direction: currentLayoutMode,
sortMethod: 'directed',
levelSeparation: currentLayoutMode === 'LR' ? 310 : 185,
nodeSpacing: currentLayoutMode === 'LR' ? 110 : 250,
treeSpacing: 130,
blockShifting: true,
edgeMinimization: true,
parentCentralization: true
}
}
: {
hierarchical: { enabled: false }
},
physics: isHierarchical
? { enabled: false }
: {
enabled: true,
barnesHut: {
gravitationalConstant: -8500,
centralGravity: 0.25,
springLength: 220,
springConstant: 0.04,
damping: 0.09
},
stabilization: { iterations: 150 }
}
};
}
/********************************************************************
* 7. DEEP NODE INSPECTOR RENDERING (MULTI-GEN + TRIZ CONVERGENCE)
********************************************************************/
function selectNode(nodeId) {
if (!rawDagData || !rawDagData.nodes[nodeId]) return;
selectedNodeId = nodeId;
const node = rawDagData.nodes[nodeId];
const isRoot = node.hop_depth === 0;
const isConvergent = node.node_type === 'convergent' || (node.parent_ids && node.parent_ids.length > 1);
// Re-render graph to update Lineage Spotlight highlighting
renderVisGraph();
if (visNetwork && visNodesDataSet.get(nodeId)) {
visNetwork.selectNodes([nodeId]);
}
// 1. Update Lineage Breadcrumb & Stepper
updateLineageBreadcrumbAndStepper(node);
// 2. Header Badges & Mutation Ratio
const hopBadge = document.getElementById('inspHopBadge');
document.getElementById('inspNodeId').textContent = node.node_id;
document.getElementById('inspMutationRatioBadge').textContent = `${node.hop_depth}/4 Pillars Mutated`;
if (isRoot) {
hopBadge.textContent = 'GEN 0 • ROOT SEED';
hopBadge.className = 'px-2.5 py-0.5 rounded text-[11px] font-mono font-bold bg-indigo-500/20 text-indigo-300 border border-indigo-500/40';
document.getElementById('inspCompositeScore').textContent = 'SACRED ANCHOR';
document.getElementById('inspCompositeScore').className = 'px-2.5 py-0.5 rounded-md font-mono font-bold text-xs bg-indigo-500/20 text-indigo-300 border border-indigo-500/40';
} else if (isConvergent) {
hopBadge.textContent = `GEN 3 • CONVERGENT (2-PARENT BRED)`;
hopBadge.className = 'px-2.5 py-0.5 rounded text-[11px] font-mono font-bold bg-fuchsia-500/25 text-fuchsia-200 border border-fuchsia-400/50';
} else {
const genColors = {
1: 'bg-sky-500/20 text-sky-300 border-sky-500/40',
2: 'bg-purple-500/20 text-purple-300 border-purple-500/40',
3: 'bg-amber-500/20 text-amber-300 border-amber-500/40'
};
hopBadge.textContent = `GEN ${node.hop_depth} • ${node.hop_depth === 3 ? 'EMERGENT PARADIGM' : 'SPIN-OFF'}`;
hopBadge.className = `px-2.5 py-0.5 rounded text-[11px] font-mono font-bold border ${genColors[node.hop_depth] || genColors[1]}`;
}
if (!isRoot) {
const score = (node.composite_score || 0).toFixed(2);
const scoreEl = document.getElementById('inspCompositeScore');
scoreEl.textContent = `${score} / 10`;
scoreEl.className = node.composite_score >= 8.3
? 'px-2.5 py-0.5 rounded-md font-mono font-bold text-xs bg-emerald-500/20 text-emerald-300 border border-emerald-500/40'
: 'px-2.5 py-0.5 rounded-md font-mono font-bold text-xs bg-sky-500/20 text-sky-300 border border-sky-500/40';
}
// 3. Title & Meta Badges
document.getElementById('inspTitle').textContent = node.title;
const metaBadges = document.getElementById('inspMetaBadges');
if (isRoot) {
metaBadges.classList.add('hidden');
metaBadges.classList.remove('flex');
} else {
metaBadges.classList.remove('hidden');
metaBadges.classList.add('flex');
document.getElementById('inspVectorBadge').textContent = node.applied_vector || 'N/A';
document.getElementById('inspMoveBadge').textContent = node.archetypal_move || 'N/A';
}
// 4. TRIZ Convergence Synthesis Card (For 2-Parent Gen 3 Nodes)
const convCard = document.getElementById('inspConvergenceCard');
if (isConvergent && node.convergence_synthesis) {
convCard.classList.remove('hidden');
const cs = node.convergence_synthesis;
document.getElementById('convParentALabel').innerHTML =
`Parent A (<button onclick="selectNode('${cs.parent_a_id}')" class="underline hover:text-white">${cs.parent_a_id}</button>):`;
document.getElementById('convParentAText').textContent = cs.parent_a_contribution;
document.getElementById('convParentBLabel').innerHTML =
`Parent B (<button onclick="selectNode('${cs.parent_b_id}')" class="underline hover:text-white">${cs.parent_b_id}</button>):`;
document.getElementById('convParentBText').textContent = cs.parent_b_contribution;
document.getElementById('convContradictionText').textContent = cs.triz_contradiction_resolved;
} else {
convCard.classList.add('hidden');
}
// 5. Summary / Scenario
document.getElementById('inspSummaryHeader').textContent = isRoot
? 'First-Principles Deconstruction (Jargon Stripped)'
: 'Concrete Deployment Scenario & Target Substrate';
document.getElementById('inspSummaryText').textContent = isRoot
? node.domain_jargon_stripped_summary
: node.concrete_application_scenario;
// 6. Latest Hop Mutation Diff
const diffBox = document.getElementById('inspMutationDiffBox');
if (isRoot) {
diffBox.classList.add('hidden');
} else {
diffBox.classList.remove('hidden');
const mutatedKey = node.mutated_pillar;
document.getElementById('inspMutatedPillarTag').textContent = mutatedKey;
document.getElementById('inspMutationExplanation').textContent = node.mutation_delta_explanation || '';
const primaryParentId = (node.parent_ids && node.parent_ids[0]) || node.parent_id;
const parentNode = rawDagData.nodes[primaryParentId];
document.getElementById('inspParentIdLabel').textContent =
node.parent_ids && node.parent_ids.length > 1 ? node.parent_ids.join(' + ') : primaryParentId;
const parentPrimitives = parentNode ? (parentNode.primitives || parentNode.updated_primitives || {}) : {};
const childPrimitives = node.updated_primitives || {};
document.getElementById('inspParentPillarText').textContent = parentPrimitives[mutatedKey] || 'N/A';
document.getElementById('inspChildPillarText').textContent = childPrimitives[mutatedKey] || 'N/A';
}
// 7. Render 4 Cumulative Functional Pillars
renderPrimitivesCards(node);
// 8. Render Generation-Adjusted Rubric
const frictionSec = document.getElementById('inspFrictionSection');
if (isRoot || !node.friction_delta) {
frictionSec.classList.add('hidden');
} else {
frictionSec.classList.remove('hidden');
const fd = node.friction_delta;
document.getElementById('inspRubricTotal').textContent = `${(node.composite_score || 0).toFixed(2)} / 10`;
document.getElementById('scorePainText').textContent = `${fd.pain_severity_score} / 10`;
document.getElementById('scorePainBar').style.width = `${fd.pain_severity_score * 10}%`;
document.getElementById('scoreFeasText').textContent = `${fd.technical_feasibility_score} / 10`;
document.getElementById('scoreFeasBar').style.width = `${fd.technical_feasibility_score * 10}%`;
document.getElementById('scoreBarrierText').textContent = `${fd.regulatory_or_adoption_barrier_reduction} / 10`;
document.getElementById('scoreBarrierBar').style.width = `${fd.regulatory_or_adoption_barrier_reduction * 10}%`;
const nov = fd.paradigm_novelty_score || 8;
document.getElementById('scoreNoveltyText').textContent = `${nov} / 10`;
document.getElementById('scoreNoveltyBar').style.width = `${nov * 10}%`;
document.getElementById('inspPhysicsCheck').textContent = fd.physics_or_logic_violation_check || 'Verified.';
}
// 9. Downstream Children
renderChildrenButtons(nodeId);
lucide.createIcons();
}
/**
* Builds both the top floating breadcrumb and the detailed Generational Stepper in the Inspector
*/
function updateLineageBreadcrumbAndStepper(node) {
// Collect all ancestor nodes sorted by generation (hop_depth 0 -> N)
const { activeNodes } = computeActiveLineageSet(node.node_id);
const ancestorNodes = Array.from(activeNodes)
.map(id => rawDagData.nodes[id])
.filter(n => n && n.hop_depth <= node.hop_depth)
.sort((a, b) => a.hop_depth - b.hop_depth);
// Update floating canvas breadcrumb
const bcEl = document.getElementById('breadcrumbText');
bcEl.innerHTML = ancestorNodes
.map(n => {
const isCurrent = n.node_id === node.node_id;
return `<button onclick="selectNode('${n.node_id}')" class="px-1.5 py-0.5 rounded ${
isCurrent ? 'bg-amber-500 text-slate-950 font-bold' : 'bg-slate-800 hover:bg-slate-700 text-cyan-300'
} transition">[Gen ${n.hop_depth}] ${n.node_id}</button>`;
})
.join(' <span class="text-slate-500">→</span> ');
// Update Inspector Stepper
const stepperContainer = document.getElementById('inspLineageStepsContainer');
stepperContainer.innerHTML = '';
ancestorNodes.forEach(anc => {
const isCurrent = anc.node_id === node.node_id;
const stepDiv = document.createElement('div');
stepDiv.className = `p-2 rounded-lg border text-xs flex items-center justify-between gap-2 cursor-pointer transition ${
isCurrent
? 'bg-amber-500/15 border-amber-500/50 text-amber-100'
: 'bg-slate-900/90 hover:bg-slate-800 border-slate-800 text-slate-300'
}`;
stepDiv.onclick = () => selectNode(anc.node_id);
if (anc.hop_depth === 0) {
stepDiv.innerHTML = `
<div class="flex items-center gap-2 truncate">
<span class="px-1.5 py-0.5 rounded bg-indigo-500/20 text-indigo-300 font-mono text-[10px] font-bold">GEN 0</span>
<span class="font-medium truncate">${anc.title}</span>
</div>
<span class="text-[10px] font-mono text-emerald-400 shrink-0">Sacred Anchor Set</span>
`;
} else {
const isConv = anc.node_type === 'convergent' || (anc.parent_ids && anc.parent_ids.length > 1);
stepDiv.innerHTML = `
<div class="flex items-center gap-2 truncate">
<span class="px-1.5 py-0.5 rounded ${
isConv ? 'bg-fuchsia-500/25 text-fuchsia-300' : 'bg-cyan-500/20 text-cyan-300'
} font-mono text-[10px] font-bold">GEN ${anc.hop_depth}</span>
<span class="font-medium truncate">${anc.title}</span>
</div>
<span class="text-[10px] font-mono text-amber-300 shrink-0">Δ ${anc.mutated_pillar}</span>
`;
}
stepperContainer.appendChild(stepDiv);
});
}
function renderPrimitivesCards(node) {
const container = document.getElementById('inspPrimitivesList');
container.innerHTML = '';
const isRoot = node.hop_depth === 0;
const primitives = isRoot ? node.primitives : node.updated_primitives;
if (!primitives) return;
const history = node.pillar_mutation_history || {};
const pillarKeys = ['input_signal', 'core_mechanism', 'governing_constraint', 'output_value'];
pillarKeys.forEach(key => {
const isSacredAnchor = key === 'core_mechanism';
const mutatedAtGen = history[key] !== undefined ? history[key] : (node.mutated_pillar === key ? node.hop_depth : 0);
const isMutatedThisHop = !isRoot && node.mutated_pillar === key;
const card = document.createElement('div');
let badgeHtml = '';
if (isSacredAnchor) {
card.className = 'rounded-xl p-3 bg-emerald-950/20 border border-emerald-500/40 transition';
badgeHtml = `<span class="px-2 py-0.5 rounded text-[10px] font-mono font-bold bg-emerald-500/20 text-emerald-300 border border-emerald-500/40">SACRED ANCHOR (GEN 0 INVARIANT)</span>`;
} else if (isMutatedThisHop) {
card.className = 'rounded-xl p-3 bg-amber-950/30 border-2 border-amber-500/70 shadow-inner transition';
badgeHtml = `<span class="px-2 py-0.5 rounded text-[10px] font-mono font-bold bg-amber-500 text-slate-950 uppercase">MUTATED AT GEN ${node.hop_depth} (ACTIVE HOP)</span>`;
} else if (mutatedAtGen > 0) {
card.className = 'rounded-xl p-3 bg-purple-950/20 border border-purple-500/40 transition';
badgeHtml = `<span class="px-2 py-0.5 rounded text-[10px] font-mono font-semibold bg-purple-500/20 text-purple-300 border border-purple-500/40">MUTATED AT GEN ${mutatedAtGen} (LOCKED NOW)</span>`;
} else {
card.className = 'rounded-xl p-3 bg-slate-950/70 border border-slate-800/90 transition';
badgeHtml = `<span class="px-2 py-0.5 rounded text-[10px] font-mono bg-slate-800 text-slate-400 border border-slate-700">LOCKED SINCE GEN 0</span>`;
}
card.innerHTML = `
<div class="flex flex-wrap items-center justify-between gap-1 mb-1">
<span class="font-mono text-xs font-semibold ${isSacredAnchor ? 'text-emerald-300' : (isMutatedThisHop ? 'text-amber-300' : 'text-slate-200')} flex items-center gap-1.5">
<i data-lucide="${isSacredAnchor ? 'anchor' : (isMutatedThisHop ? 'zap' : 'lock')}" class="w-3.5 h-3.5"></i>
${PILLAR_LABELS[key]}
</span>
${badgeHtml}
</div>
<p class="text-xs ${isMutatedThisHop ? 'text-amber-100' : 'text-slate-300'} leading-relaxed">${primitives[key] || ''}</p>
`;
container.appendChild(card);
});
}
function renderChildrenButtons(parentId) {
const children = Object.values(rawDagData.nodes).filter(n => {
const pIds = n.parent_ids || (n.parent_id ? [n.parent_id] : []);
return pIds.includes(parentId);
});
const countEl = document.getElementById('inspChildrenCount');
const listEl = document.getElementById('inspChildrenList');
const secEl = document.getElementById('inspChildrenSection');
countEl.textContent = children.length;
listEl.innerHTML = '';
if (children.length === 0) {
secEl.classList.add('hidden');
return;
}
secEl.classList.remove('hidden');
children.forEach(child => {
const isConv = child.node_type === 'convergent' || (child.parent_ids && child.parent_ids.length > 1);
const btn = document.createElement('button');
const score = (child.composite_score || 0).toFixed(2);
btn.onclick = () => selectNode(child.node_id);
btn.className = 'w-full text-left px-3 py-2 rounded-lg bg-slate-950 hover:bg-slate-800 border border-slate-800 hover:border-cyan-500/40 flex items-center justify-between gap-2 transition group';
btn.innerHTML = `
<div class="truncate">
<div class="text-xs font-medium text-slate-200 group-hover:text-cyan-300 truncate">
[Gen ${child.hop_depth}${isConv ? ' Bred' : ''}] ${child.title}
</div>
<div class="text-[10px] font-mono text-slate-500">${child.applied_vector} • Δ ${child.mutated_pillar}</div>
</div>
<span class="shrink-0 px-2 py-0.5 rounded font-mono text-[11px] font-semibold bg-slate-900 text-cyan-400 border border-slate-700">
★ ${score}
</span>
`;
listEl.appendChild(btn);
});
}
/********************************************************************
* 8. TOOLBAR & LEGEND INTERACTIONS
********************************************************************/
function setColorMode(mode) {
currentColorMode = mode;
const modes = {
hop: document.getElementById('modeHopBtn'),
viability: document.getElementById('modeViabilityBtn'),
vector: document.getElementById('modeVectorBtn')
};
Object.keys(modes).forEach(k => {
if (k === mode) {
modes[k].className = 'px-2.5 py-1.5 rounded-md text-xs font-medium transition-all flex items-center gap-1.5 bg-cyan-600 text-white shadow';
} else {
modes[k].className = 'px-2.5 py-1.5 rounded-md text-xs font-medium transition-all flex items-center gap-1.5 text-slate-400 hover:text-slate-200';
}
});
renderVisGraph();
}
function setLayoutMode(layout) {
currentLayoutMode = layout;
const btns = {
LR: document.getElementById('layoutLRBtn'),
UD: document.getElementById('layoutUDBtn'),
FORCE: document.getElementById('layoutForceBtn')
};
Object.keys(btns).forEach(k => {
if (k === layout) {
btns[k].className = 'px-2.5 py-1 rounded bg-slate-800 text-cyan-400 font-mono font-medium transition';
} else {
btns[k].className = 'px-2.5 py-1 rounded text-slate-400 hover:text-slate-200 font-mono transition';
}
});
renderVisGraph();
setTimeout(() => fitGraph(), 200);
}
function applyFilters() {
const val = parseFloat(document.getElementById('minScoreSlider').value).toFixed(2);
document.getElementById('minScoreValue').textContent = val;
renderVisGraph();
}
function updateLegend() {
const legendEl = document.getElementById('legendContent');
if (currentColorMode === 'hop') {
legendEl.innerHTML = `
<span class="font-mono uppercase text-slate-400 font-semibold">Generational Hierarchy:</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-indigo-900 border border-indigo-400 inline-block"></span>Gen 0: Root Anchor</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-sky-900 border border-sky-400 inline-block"></span>Gen 1: Spin-Off (1/4)</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-purple-950 border border-purple-400 inline-block"></span>Gen 2: Hybrid (2/4)</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-amber-900 border border-amber-400 inline-block"></span>Gen 3: Divergent (3/4)</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-fuchsia-900 border border-dashed border-pink-400 inline-block"></span>Gen 3: TRIZ Convergent (2-Parent Bred)</span>
`;
} else if (currentColorMode === 'viability') {
legendEl.innerHTML = `
<span class="font-mono uppercase text-slate-400 font-semibold">Emergence Score Heatmap:</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-indigo-900 border border-indigo-400 inline-block"></span>Root Seed</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-emerald-900 border border-emerald-400 inline-block"></span>Breakthrough (≥8.8)</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-sky-900 border border-sky-400 inline-block"></span>Strong (8.0–8.79)</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-amber-900 border border-amber-400 inline-block"></span>Moderate (7.0–7.99)</span>
<span class="flex items-center gap-1.5"><span class="w-3 h-3 rounded-sm bg-rose-900 border border-rose-400 inline-block"></span>High Friction (<7.0)</span>
`;
} else {
legendEl.innerHTML = Object.entries(VECTOR_PALETTE).map(([vec, pal]) => `
<span class="flex items-center gap-1.5">
<span class="w-3 h-3 rounded-sm inline-block" style="background:${pal.bg}; border:1px solid ${pal.border}"></span>
<span>${pal.short}</span>
</span>
`).join('');
}
}
function fitGraph() {
if (visNetwork) {
visNetwork.fit({ animation: { duration: 400, easingFunction: 'easeInOutQuad' } });
}
}
function zoomGraph(factor) {
if (!visNetwork) return;
const currentScale = visNetwork.getScale();
visNetwork.moveTo({ scale: currentScale * factor, animation: { duration: 200 } });
}
/********************************************************************
* 8. FILE UPLOAD, DRAG-AND-DROP, PASTE MODAL & EXPORT
********************************************************************/
function handleFileSelect(event) {
const file = event.target.files[0];
if (!file) return;
readJsonFile(file);
}
function readJsonFile(file) {
const reader = new FileReader();
reader.onload = (e) => {
try {
const parsed = JSON.parse(e.target.result);
loadCustomDagObject(parsed, file.name);
} catch (err) {
showToast(`Invalid JSON file: ${err.message}`, true);
}
};
reader.readAsText(file);
}
function setupDragAndDrop() {
const wrapper = document.getElementById('canvasWrapper');
const overlay = document.getElementById('dropOverlay');
wrapper.addEventListener('dragover', (e) => {
e.preventDefault();
overlay.classList.remove('hidden');
});
wrapper.addEventListener('dragleave', (e) => {
e.preventDefault();
overlay.classList.add('hidden');
});
wrapper.addEventListener('drop', (e) => {
e.preventDefault();
overlay.classList.add('hidden');
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
readJsonFile(e.dataTransfer.files[0]);
}
});
}
function loadCustomDagObject(parsed, sourceLabel = 'Custom JSON') {
if (!parsed || typeof parsed.nodes !== 'object') {
throw new Error('JSON must contain a top-level "nodes" dictionary.');
}
// If edges array is missing, reconstruct edges from parent_ids or parent_id references
if (!Array.isArray(parsed.edges)) {
parsed.edges = [];
Object.values(parsed.nodes).forEach(n => {
const parents = n.parent_ids || (n.parent_id ? [n.parent_id] : []);
parents.forEach(pId => {
if (parsed.nodes[pId]) {
parsed.edges.push({
source: pId,
target: n.node_id,
vector: n.applied_vector || '',
mutated_pillar: n.mutated_pillar || '',
is_convergent: parents.length > 1
});
}
});
});
}
rawDagData = parsed;
normalizeAndValidateDAG(rawDagData);
populateGen3QuickJump();
const nodeKeys = Object.keys(rawDagData.nodes);
const rootId = rawDagData.nodes['root_0'] ? 'root_0' : nodeKeys[0];
document.getElementById('datasetTitleDisplay').textContent =
`Loaded: ${rawDagData.nodes[rootId]?.title || sourceLabel} (${nodeKeys.length} Nodes)`;
renderVisGraph();
if (rootId) selectNode(rootId);
setTimeout(() => fitGraph(), 250);
showToast(`Loaded ${nodeKeys.length} nodes from ${sourceLabel}`);
}
function openPasteModal() {
const modal = document.getElementById('pasteModal');
const textarea = document.getElementById('jsonPasteTextarea');
document.getElementById('jsonErrorBanner').classList.add('hidden');
textarea.value = JSON.stringify(rawDagData, null, 2);
modal.classList.remove('hidden');
}
function closePasteModal() {
document.getElementById('pasteModal').classList.add('hidden');
}
function formatModalJSON() {
const textarea = document.getElementById('jsonPasteTextarea');
const errBanner = document.getElementById('jsonErrorBanner');
try {
const obj = JSON.parse(textarea.value);
textarea.value = JSON.stringify(obj, null, 2);
errBanner.classList.add('hidden');
} catch (err) {
errBanner.textContent = `Syntax Error: ${err.message}`;
errBanner.classList.remove('hidden');
}
}
function applyPastedJSON() {
const textarea = document.getElementById('jsonPasteTextarea');
const errBanner = document.getElementById('jsonErrorBanner');
try {
const parsed = JSON.parse(textarea.value);
loadCustomDagObject(parsed, 'Pasted JSON');
closePasteModal();
} catch (err) {
errBanner.textContent = `Validation Error: ${err.message}`;
errBanner.classList.remove('hidden');
}
}
function exportFilteredJSON() {
if (!rawDagData) return;
const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(rawDagData, null, 2));
const dlAnchor = document.createElement('a');
dlAnchor.setAttribute("href", dataStr);
dlAnchor.setAttribute("download", "adjacency_idea_dag.json");
document.body.appendChild(dlAnchor);
dlAnchor.click();
dlAnchor.remove();
showToast("Exported adjacency_idea_dag.json");
}
function showToast(msg, isError = false) {
const banner = document.getElementById('toastBanner');
const text = document.getElementById('toastMessage');
text.textContent = msg;
banner.className = `fixed bottom-14 left-1/2 -translate-x-1/2 px-4 py-2 rounded-xl bg-slate-900/95 border ${
isError ? 'border-rose-500/60 text-rose-200' : 'border-cyan-500/40 text-cyan-200'
} text-xs font-mono shadow-2xl z-50 transition-all duration-300 opacity-100 flex items-center gap-2`;
setTimeout(() => {
banner.classList.replace('opacity-100', 'opacity-0');
}, 3200);
}
</script>
</body>
</html>
Jupyter Notebook .ipynb file





Comments
Post a Comment