# Adaptation Catalog > Compare every cell adaptation and its quality tiers side by side — the verification surface for the evolution system, with live eyespot vision previews. --- .. toc:: ### The adaptation set Every cell part has four quality **tiers** (`none / poor / decent / great`) that map to a stat multiplier and a cost. A *poor* tier is an **active liability** (negative multiplier — wasted ATP, drag), a *great* tier is powerful but expensive. This catalog is generated from one data model (`lib/adaptations.py`) so each adaptation can be verified in isolation as the set grows. .. admonition::Eyespot is live :color: blue The **eyespot** is the first part wired into the [Petri Dish Game](/petri-dish-game). Its tiers below render a live mini-preview of how each one shows the game world — from a blind green **radar**, through a blurry grayscale view, to wide full-colour sight. Roll for one in the [Eyespot Lab](/adaptation-eyespot). .. exec::docs.adaptations_catalog.adaptations_catalog :code: false ### Source ```python # File: docs/adaptations_catalog/adaptations_catalog.py from dash import dcc, html, clientside_callback, Input, Output, State import dash_mantine_components as dmc from dash_iconify import DashIconify from lib.adaptations import ADAPTATIONS, PART_ORDER, TIER_COLOR, TIER_LABEL, EYESPOT_VISION # /adaptations — a side-by-side CATALOG of every cell adaptation and its quality # tiers, built straight from lib/adaptations.py. It's the verification surface: # as eyespot variants (and later other parts) are added, each shows here in # isolation — including a live mini-preview of how each EYESPOT tier renders the # game's viewport (radar / blur / muted / full) without playing the game. ACCENT = "#3399ff" _ROLE_COLOR = {"speed": "blue", "sense": "grape", "defense": "orange", "attack": "red", "feed": "green", "grip": "teal"} # parts that have their own interactive lab page (catalog header links there). _LAB_ROUTES = {"eyespot": "/adaptation-eyespot", "flagellum": "/adaptation-flagellum", "cilia": "/adaptation-cilia", "membrane": "/adaptation-membrane", "filter": "/adaptation-filter", "jaw": "/adaptation-jaw", "proboscis": "/adaptation-proboscis", "pseudopod": "/adaptation-pseudopod", "spike": "/adaptation-spike", "stinger": "/adaptation-stinger"} # fixed mini-scene (world coords, player centred) reused for every eyespot preview _SCENE = [ {"x": -150, "y": -110, "r": 70, "img": "/assets/petri/paramecium.svg", "kind": "food", "deg": 25}, {"x": 360, "y": -180, "r": 120, "img": "/assets/petri/cyclops.svg", "kind": "hunter", "deg": 210, "ring": True}, {"x": 240, "y": 300, "r": 64, "img": "/assets/petri/euglena.svg", "kind": "food", "deg": -100}, {"x": -420, "y": 260, "r": 96, "img": "/assets/petri/daphnia.svg", "kind": "threat", "deg": 135}, {"x": -640, "y": -480, "r": 60, "img": "/assets/petri/navicula.svg", "kind": "food", "deg": 60}, {"x": 700, "y": 520, "r": 80, "img": "/assets/petri/stentor.svg", "kind": "threat", "deg": 250}, {"x": 0, "y": 0, "r": 64, "img": "/assets/petri/volvox.svg", "kind": "player", "deg": 0, "ring": True}, ] _PLANKTON = [{"x": gx * 130 - 845, "y": gy * 130 - 845, "s": 16} for gx in range(14) for gy in range(14) if (gx * 7 + gy * 3) % 3 == 0] def _variant_card(part_id, v): is_eye = part_id == "eyespot" # eyespot cards preview the in-game VISION; every other part previews a # schematic of the organelle at this tier (window.CV.renderPart). pid = ({"type": "cat-eye", "tier": v["tier"]} if is_eye else {"type": "cat-part", "part": part_id, "tier": v["tier"]}) body = [ # wrap allowed: at the phone-grid widths (~100px cards) the badge and the # name stack instead of overflowing dmc.Group( [dmc.Badge(TIER_LABEL[v["tier"]], color=TIER_COLOR[v["tier"]], variant="light", size="sm"), dmc.Text(v["name"], fw=600, size="sm")], justify="space-between", gap=4, ), html.Div(id=pid, className="petri-dish", style={"width": "100%", "aspectRatio": "1 / 1", "borderRadius": "10px", "overflow": "hidden", "margin": "6px 0"}), ] body.append(dmc.Text(v["blurb"], size="xs", c="dimmed")) body.append(dmc.Group( [dmc.Text(f"stat {v['mult']:+.1f}", size="xs", fw=600, c="red" if v["mult"] < 0 else ("dimmed" if v["mult"] == 0 else "teal"), style={"fontFamily": "monospace"}), dmc.Text(f"cost {v['cost']:.2f}", size="xs", c="dimmed", style={"fontFamily": "monospace"})], justify="space-between", gap=4)) return dmc.Paper(body, withBorder=True, radius="md", p={"base": 6, "sm": "sm"}) def _part_card(part_id): part = ADAPTATIONS[part_id] is_eye = part_id == "eyespot" variants = part["variants"] if is_eye else [v for v in part["variants"] if v["tier"] != "none"] route = _LAB_ROUTES.get(part_id) badges = [dmc.Badge(part["role"], color=_ROLE_COLOR.get(part["role"], "gray"), variant="light", size="xs")] if part.get("diet"): badges.append(dmc.Badge(part["diet"], color="lime", variant="dot", size="xs")) badges.append( dmc.Anchor(dmc.Badge("open lab →", color="brand", variant="filled", size="xs"), href=route) if route else dmc.Badge("lab soon", color="gray", variant="light", size="xs")) _label_style = {"letterSpacing": "1px", "fontFamily": "monospace"} title = (dmc.Anchor(part["label"], href=route, fw=700, c=ACCENT, style=_label_style) if route else dmc.Text(part["label"], fw=700, c=ACCENT, style=_label_style)) return dmc.Paper( [ dmc.Group( [dmc.Group([DashIconify(icon=part["icon"], width=22, color=ACCENT), title], gap=8), dmc.Group(badges, gap=6)], justify="space-between", mb=4, ), dmc.Text(part["function"], size="sm", c="dimmed", mb="xs"), # phones: keep the whole tier group on screen — 2×2 for the 4-tier eyespot # (none/poor/decent/great), one row of 3 for poor/decent/great parts. # md+ keeps the original single-row layout. dmc.SimpleGrid(cols={"base": 2 if is_eye else 3, "md": 4 if is_eye else 3}, spacing={"base": 6, "md": "sm"}, children=[_variant_card(part_id, v) for v in variants]), ], withBorder=True, radius="md", p="md", mb="md", style={"borderColor": "rgb(51 142 234 / 24%)"}, ) component = dmc.Stack( [ dmc.Paper( [ dmc.Text("ADAPTATION CATALOG", fw=700, c=ACCENT, style={"letterSpacing": "2px", "fontFamily": "monospace"}), dmc.Text("Every cell adaptation and its quality tiers, from one data model. " "Each tier maps to a stat multiplier (poor tiers are an active liability) and a " "cost. The eyespot is wired into the Petri Dish Game — its tiers below show a live " "preview of how each one renders the game viewport.", size="sm", c="dimmed"), ], withBorder=True, radius="md", p="md", style={"borderColor": "rgb(51 142 234 / 24%)", "background": "linear-gradient(rgb(255 255 255 / 0%) 0%, rgb(243 247 239 / 30%) 100%)"}, ), *[_part_card(pid) for pid in PART_ORDER], dcc.Store(id="cat-scene", data=_SCENE), dcc.Store(id="cat-plankton", data=_PLANKTON), dcc.Store(id="cat-vis", data=EYESPOT_VISION), dcc.Store(id="cat-sink"), dcc.Interval(id="cat-init", interval=300, max_intervals=1), ], gap="md", ) # Render the eyespot tier previews via the shared CV renderer once the page mounts. clientside_callback( """ function(_n, scene, plankton, vis) { if (!window.CV || !vis) { return window.dash_clientside.no_update; } // Dash renders pattern-matching ids as JSON strings, e.g. // id='{"tier":"none","type":"cat-eye"}'. Eyespot tiers preview the game // VISION; every other part previews a schematic via CV.renderPart. document.querySelectorAll('[id*="cat-eye"]').forEach(host => { let tier = null; try { tier = JSON.parse(host.id).tier; } catch (e) { return; } const v = vis[tier]; if (!v) { return; } host.innerHTML = window.CV.renderArena({ vb: [-v.view, -v.view, 2 * v.view, 2 * v.view], style: v.style, cells: scene, plankton: plankton, cam: {x: 0, y: 0, vr: v.view}, t: 7, }); }); document.querySelectorAll('[id*="cat-part"]').forEach(host => { let id = null; try { id = JSON.parse(host.id); } catch (e) { return; } // game-accurate SCENE (cell + organelle + a gameplay hint) — matches the // eyespot cards' polish instead of a bare schematic. host.innerHTML = (window.CV.renderAdaptPreview || window.CV.renderPart)(id.part, id.tier); }); return ''; } """, Output("cat-sink", "data"), Input("cat-init", "n_intervals"), State("cat-scene", "data"), State("cat-plankton", "data"), State("cat-vis", "data"), ) ``` :defaultExpanded: false :withExpandedButton: true --- *Source: /adaptations*