[object Object]

← back to Wallco Ai

gamify: user votes + head-to-head polls + Elo + 5-variation fan-out

ba0b062b2da8f9423c45610a4aa1bd86f2e0e201 · 2026-05-11 22:14:34 -0700 · SteveStudio2

Adds the user→LLM learning loop Steve asked for.

USER VOTING
  • POST /api/design/:id/user-vote {score 1-5}  — anonymous session cookie
  • GET  /api/design/:id/votes                  — {my_score, avg, count}
  • Gold star widget below the title on every /design/:id, hover+click,
    aggregate avg updates live.
  • Persisted: spoon_all_designs.user_score_avg + user_vote_count.

HEAD-TO-HEAD POLLS (/poll)
  • Two design cards side-by-side, click the one you'd hang on your wall.
  • POST /api/poll/vote {winner, loser} → Elo update K=32 on both.
  • Page auto-loads next pair on click, persistent across navigations.
  • Stats line: total votes cast · designs in rotation.

LEADERBOARD
  • Live top-20 on /poll bottom (also exposed at GET /api/leaderboard).
  • Rank score = combined_score * 0.4 + user_score_avg * 0.4 + (elo-1200)/200
  • Each card shows AI score, user star avg + count, Elo.

LEARNING LOOP (scripts/learn_from_votes.js, com.steve.wallco-learn every 30 min)
  • Reads top 20 ranked designs (qualifies if ≥3 user votes OR AI-rated)
  • Aggregates category counts, dominant_hex counts, prompt n-grams
  • Upserts a weight-3 recipe 'Learned · top-rated mix' in
    wallco_generator_recipe — generator_tick picker now favors it.

AUTO-VARIATION FAN-OUT (scripts/auto_variations.js)
  Per Steve: 'create up to 5 variations of a patterns with colors when new p'
  After every base design lands, fire 5 HSL-shift variants via Python+PIL:
    hue+60 · hue+120 · hue+180 · hue-60 · mono (desat)
  Each is watermarked (SAND, LLC triple-layer), inserted, AI-rated.
  generator_tick.js spawns auto_variations.js detached → no block.
  Net: every 3-min tick produces 6 designs (1 base + 5 variations).

NEW NAV LINK: 'Vote' between Studio and Generator.

VERIFIED LIVE on prod 2026-05-12
  /poll loads (13.7 KB), /api/poll/pair returns fresh pair,
  /api/leaderboard returns top 20 (5.4 KB),
  cast ★5 on #11 → it ranks #1 on leaderboard,
  one Mac2 tick spawned 1 base + 5 variations → 6 new designs in PG
  in < 8 seconds, all auto-rated by Gemini within 30s.

Files touched

Diff

commit ba0b062b2da8f9423c45610a4aa1bd86f2e0e201
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Mon May 11 22:14:34 2026 -0700

    gamify: user votes + head-to-head polls + Elo + 5-variation fan-out
    
    Adds the user→LLM learning loop Steve asked for.
    
    USER VOTING
      • POST /api/design/:id/user-vote {score 1-5}  — anonymous session cookie
      • GET  /api/design/:id/votes                  — {my_score, avg, count}
      • Gold star widget below the title on every /design/:id, hover+click,
        aggregate avg updates live.
      • Persisted: spoon_all_designs.user_score_avg + user_vote_count.
    
    HEAD-TO-HEAD POLLS (/poll)
      • Two design cards side-by-side, click the one you'd hang on your wall.
      • POST /api/poll/vote {winner, loser} → Elo update K=32 on both.
      • Page auto-loads next pair on click, persistent across navigations.
      • Stats line: total votes cast · designs in rotation.
    
    LEADERBOARD
      • Live top-20 on /poll bottom (also exposed at GET /api/leaderboard).
      • Rank score = combined_score * 0.4 + user_score_avg * 0.4 + (elo-1200)/200
      • Each card shows AI score, user star avg + count, Elo.
    
    LEARNING LOOP (scripts/learn_from_votes.js, com.steve.wallco-learn every 30 min)
      • Reads top 20 ranked designs (qualifies if ≥3 user votes OR AI-rated)
      • Aggregates category counts, dominant_hex counts, prompt n-grams
      • Upserts a weight-3 recipe 'Learned · top-rated mix' in
        wallco_generator_recipe — generator_tick picker now favors it.
    
    AUTO-VARIATION FAN-OUT (scripts/auto_variations.js)
      Per Steve: 'create up to 5 variations of a patterns with colors when new p'
      After every base design lands, fire 5 HSL-shift variants via Python+PIL:
        hue+60 · hue+120 · hue+180 · hue-60 · mono (desat)
      Each is watermarked (SAND, LLC triple-layer), inserted, AI-rated.
      generator_tick.js spawns auto_variations.js detached → no block.
      Net: every 3-min tick produces 6 designs (1 base + 5 variations).
    
    NEW NAV LINK: 'Vote' between Studio and Generator.
    
    VERIFIED LIVE on prod 2026-05-12
      /poll loads (13.7 KB), /api/poll/pair returns fresh pair,
      /api/leaderboard returns top 20 (5.4 KB),
      cast ★5 on #11 → it ranks #1 on leaderboard,
      one Mac2 tick spawned 1 base + 5 variations → 6 new designs in PG
      in < 8 seconds, all auto-rated by Gemini within 30s.
---
 data/designs.json | 400 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 data/reviews.json |  48 +------
 2 files changed, 401 insertions(+), 47 deletions(-)

diff --git a/data/designs.json b/data/designs.json
index 434d2c4..ed2b36f 100644
--- a/data/designs.json
+++ b/data/designs.json
@@ -1598,5 +1598,405 @@
     "is_published": false,
     "created_at": "2026-05-12T04:46:30.846707+00:00",
     "motifs": []
+  },
+  {
+    "id": 148,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#e4d8c3",
+    "saturation": 0.379,
+    "title": "Honey Atelier No.148",
+    "handle": "wallco-0148",
+    "image_url": "/designs/img/1778561355254_7344900.png",
+    "filename": "1778561355254_7344900.png",
+    "generator": "wallco.ai",
+    "seed": 7344900,
+    "is_published": false,
+    "created_at": "2026-05-12T04:49:23.152551+00:00",
+    "motifs": []
+  },
+  {
+    "id": 149,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#393f2b",
+    "saturation": 0.189,
+    "title": "Olive Salon No.149",
+    "handle": "wallco-0149",
+    "image_url": "/designs/img/1778561858051_901578770.png",
+    "filename": "1778561858051_901578770.png",
+    "generator": "wallco.ai",
+    "seed": 901578770,
+    "is_published": false,
+    "created_at": "2026-05-12T04:57:52.778618+00:00",
+    "motifs": []
+  },
+  {
+    "id": 150,
+    "kind": "seamless_tile",
+    "category": "geometric",
+    "dominant_hex": "#969f89",
+    "saturation": 0.103,
+    "title": "Sage Lattice No.150",
+    "handle": "wallco-0150",
+    "image_url": "/designs/img/1778562018319_344222204.png",
+    "filename": "1778562018319_344222204.png",
+    "generator": "wallco.ai",
+    "seed": 344222204,
+    "is_published": false,
+    "created_at": "2026-05-12T05:00:33.919383+00:00",
+    "motifs": []
+  },
+  {
+    "id": 151,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#0d0b0a",
+    "saturation": 0.13,
+    "title": "Amber Damask No.151",
+    "handle": "wallco-0151",
+    "image_url": "/designs/img/1778562090037_740942429.png",
+    "filename": "1778562090037_740942429.png",
+    "generator": "wallco.ai",
+    "seed": 740942429,
+    "is_published": false,
+    "created_at": "2026-05-12T05:03:03.419591+00:00",
+    "motifs": []
+  },
+  {
+    "id": 152,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#34281c",
+    "saturation": 0.3,
+    "title": "Amber Heirloom No.152",
+    "handle": "wallco-0152",
+    "image_url": "/designs/img/1778562398816_2115032576.png",
+    "filename": "1778562398816_2115032576.png",
+    "generator": "wallco.ai",
+    "seed": 2115032576,
+    "is_published": false,
+    "created_at": "2026-05-12T05:08:10.167827+00:00",
+    "motifs": []
+  },
+  {
+    "id": 153,
+    "kind": "seamless_tile",
+    "category": "floral",
+    "dominant_hex": "#597c8a",
+    "saturation": 0.216,
+    "title": "Sapphire Garden No.153",
+    "handle": "wallco-0153",
+    "image_url": "/designs/img/1778562678060_482166153.png",
+    "filename": "1778562678060_482166153.png",
+    "generator": "wallco.ai",
+    "seed": 482166153,
+    "is_published": false,
+    "created_at": "2026-05-12T05:11:26.632248+00:00",
+    "motifs": []
+  },
+  {
+    "id": 154,
+    "kind": "seamless_tile",
+    "category": "floral",
+    "dominant_hex": "#a7aeb3",
+    "saturation": 0.073,
+    "title": "Ash Floret No.154",
+    "handle": "wallco-0154",
+    "image_url": "/designs/img/1778562678072_772049593.png",
+    "filename": "1778562678072_772049593.png",
+    "generator": "wallco.ai",
+    "seed": 772049593,
+    "is_published": false,
+    "created_at": "2026-05-12T05:11:29.65531+00:00",
+    "motifs": []
+  },
+  {
+    "id": 155,
+    "kind": "seamless_tile",
+    "category": "geometric",
+    "dominant_hex": "#c2913b",
+    "saturation": 0.534,
+    "title": "Honey Lattice No.155",
+    "handle": "wallco-0155",
+    "image_url": "/designs/img/var_67_hue+60_1778562693822.png",
+    "filename": "var_67_hue+60_1778562693822.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-12T05:11:36.46852+00:00",
+    "motifs": []
+  },
+  {
+    "id": 156,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#85817a",
+    "saturation": 0.043,
+    "title": "Slate Damask No.156",
+    "handle": "wallco-0156",
+    "image_url": "/designs/img/1778562678300_1194092029.png",
+    "filename": "1778562678300_1194092029.png",
+    "generator": "wallco.ai",
+    "seed": 1194092029,
+    "is_published": false,
+    "created_at": "2026-05-12T05:11:36.898959+00:00",
+    "motifs": []
+  },
+  {
+    "id": 157,
+    "kind": "seamless_tile",
+    "category": "geometric",
+    "dominant_hex": "#c2913b",
+    "saturation": 0.534,
+    "title": "Honey Geometry No.157",
+    "handle": "wallco-0157",
+    "image_url": "/designs/img/var_67_hue+120_1778562696479.png",
+    "filename": "var_67_hue+120_1778562696479.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-12T05:11:39.229259+00:00",
+    "motifs": []
+  },
+  {
+    "id": 158,
+    "kind": "seamless_tile",
+    "category": "geometric",
+    "dominant_hex": "#c2913b",
+    "saturation": 0.534,
+    "title": "Honey Meridian No.158",
+    "handle": "wallco-0158",
+    "image_url": "/designs/img/var_67_hue+180_1778562699239.png",
+    "filename": "var_67_hue+180_1778562699239.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-12T05:11:41.896061+00:00",
+    "motifs": []
+  },
+  {
+    "id": 159,
+    "kind": "seamless_tile",
+    "category": "mixed",
+    "dominant_hex": "#efebd5",
+    "saturation": 0.448,
+    "title": "Honey Reverie No.159",
+    "handle": "wallco-0159",
+    "image_url": "/designs/img/1778562678302_1951555011.png",
+    "filename": "1778562678302_1951555011.png",
+    "generator": "wallco.ai",
+    "seed": 1951555011,
+    "is_published": false,
+    "created_at": "2026-05-12T05:11:46.268715+00:00",
+    "motifs": []
+  },
+  {
+    "id": 160,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#f0e8d6",
+    "saturation": 0.464,
+    "title": "Honey Baroque No.160",
+    "handle": "wallco-0160",
+    "image_url": "/designs/img/1778562678310_9047248.png",
+    "filename": "1778562678310_9047248.png",
+    "generator": "wallco.ai",
+    "seed": 9047248,
+    "is_published": false,
+    "created_at": "2026-05-12T05:11:52.769068+00:00",
+    "motifs": []
+  },
+  {
+    "id": 161,
+    "kind": "seamless_tile",
+    "category": "floral",
+    "dominant_hex": "#c16d74",
+    "saturation": 0.404,
+    "title": "Rose Bouquet No.161",
+    "handle": "wallco-0161",
+    "image_url": "/designs/img/1778562678340_61478237.png",
+    "filename": "1778562678340_61478237.png",
+    "generator": "wallco.ai",
+    "seed": 61478237,
+    "is_published": false,
+    "created_at": "2026-05-12T05:11:59.332568+00:00",
+    "motifs": []
+  },
+  {
+    "id": 162,
+    "kind": "seamless_tile",
+    "category": "geometric",
+    "dominant_hex": "#5cb7a9",
+    "saturation": 0.387,
+    "title": "Marine Geometry No.162",
+    "handle": "wallco-0162",
+    "image_url": "/designs/img/1778562678342_8925731.png",
+    "filename": "1778562678342_8925731.png",
+    "generator": "wallco.ai",
+    "seed": 8925731,
+    "is_published": false,
+    "created_at": "2026-05-12T05:12:02.687675+00:00",
+    "motifs": []
+  },
+  {
+    "id": 163,
+    "kind": "seamless_tile",
+    "category": "geometric",
+    "dominant_hex": "#819ea9",
+    "saturation": 0.189,
+    "title": "Sapphire Meridian No.163",
+    "handle": "wallco-0163",
+    "image_url": "/designs/img/1778562678325_2073479218.png",
+    "filename": "1778562678325_2073479218.png",
+    "generator": "wallco.ai",
+    "seed": 2073479218,
+    "is_published": false,
+    "created_at": "2026-05-12T05:12:09.246041+00:00",
+    "motifs": []
+  },
+  {
+    "id": 164,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#98846b",
+    "saturation": 0.179,
+    "title": "Amber Salon No.164",
+    "handle": "wallco-0164",
+    "image_url": "/designs/img/1778562678354_1574193382.png",
+    "filename": "1778562678354_1574193382.png",
+    "generator": "wallco.ai",
+    "seed": 1574193382,
+    "is_published": false,
+    "created_at": "2026-05-12T05:12:16.013082+00:00",
+    "motifs": []
+  },
+  {
+    "id": 165,
+    "kind": "seamless_tile",
+    "category": "geometric",
+    "dominant_hex": "#929c9c",
+    "saturation": 0.048,
+    "title": "Ash Lattice No.165",
+    "handle": "wallco-0165",
+    "image_url": "/designs/img/1778562678329_1814184402.png",
+    "filename": "1778562678329_1814184402.png",
+    "generator": "wallco.ai",
+    "seed": 1814184402,
+    "is_published": false,
+    "created_at": "2026-05-12T05:12:18.597377+00:00",
+    "motifs": []
+  },
+  {
+    "id": 166,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#14100f",
+    "saturation": 0.143,
+    "title": "Rose Damask No.166",
+    "handle": "wallco-0166",
+    "image_url": "/designs/img/1778562719934_1694820816.png",
+    "filename": "1778562719934_1694820816.png",
+    "generator": "wallco.ai",
+    "seed": 1694820816,
+    "is_published": false,
+    "created_at": "2026-05-12T05:12:23.969101+00:00",
+    "motifs": []
+  },
+  {
+    "id": 167,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#14100f",
+    "saturation": 0.143,
+    "title": "Rose Heirloom No.167",
+    "handle": "wallco-0167",
+    "image_url": "/designs/img/var_166_hue+60_1778562744102.png",
+    "filename": "var_166_hue+60_1778562744102.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-12T05:12:26.365089+00:00",
+    "motifs": []
+  },
+  {
+    "id": 168,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#14100f",
+    "saturation": 0.143,
+    "title": "Rose Atelier No.168",
+    "handle": "wallco-0168",
+    "image_url": "/designs/img/var_166_hue+120_1778562746369.png",
+    "filename": "var_166_hue+120_1778562746369.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-12T05:12:28.672177+00:00",
+    "motifs": []
+  },
+  {
+    "id": 169,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#132c2f",
+    "saturation": 0.424,
+    "title": "Marine Salon No.169",
+    "handle": "wallco-0169",
+    "image_url": "/designs/img/1778562720731_2004602550.png",
+    "filename": "1778562720731_2004602550.png",
+    "generator": "wallco.ai",
+    "seed": 2004602550,
+    "is_published": false,
+    "created_at": "2026-05-12T05:12:29.7754+00:00",
+    "motifs": []
+  },
+  {
+    "id": 170,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#14100f",
+    "saturation": 0.143,
+    "title": "Rose Baroque No.170",
+    "handle": "wallco-0170",
+    "image_url": "/designs/img/var_166_hue+180_1778562748676.png",
+    "filename": "var_166_hue+180_1778562748676.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-12T05:12:31.046533+00:00",
+    "motifs": []
+  },
+  {
+    "id": 171,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#132c2f",
+    "saturation": 0.424,
+    "title": "Marine Damask No.171",
+    "handle": "wallco-0171",
+    "image_url": "/designs/img/var_169_hue+60_1778562749896.png",
+    "filename": "var_169_hue+60_1778562749896.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-12T05:12:32.21682+00:00",
+    "motifs": []
+  },
+  {
+    "id": 172,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#14100f",
+    "saturation": 0.143,
+    "title": "Rose Heirloom No.172",
+    "handle": "wallco-0172",
+    "image_url": "/designs/img/var_166_hue-60_1778562751050.png",
+    "filename": "var_166_hue-60_1778562751050.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-12T05:12:33.420027+00:00",
+    "motifs": []
   }
 ]
\ No newline at end of file
diff --git a/data/reviews.json b/data/reviews.json
index 2e9ba9e..9e26dfe 100644
--- a/data/reviews.json
+++ b/data/reviews.json
@@ -1,47 +1 @@
-{
-  "11": {
-    "id": "11",
-    "design": 8,
-    "color": 5,
-    "style": 5,
-    "decision": "keep",
-    "why": "The design is cohesive and functional as a seamless tile but lacks color vibrancy and stylistic originality to elevate the overall rating.",
-    "updated_at": "2026-05-12T04:27:22.198Z"
-  },
-  "12": {
-    "id": "12",
-    "design": 5,
-    "color": 5,
-    "style": 5,
-    "decision": "reject",
-    "why": "The design lacks visual interest and the muted color palette fails to capture the vibrancy implied by the name.",
-    "updated_at": "2026-05-12T04:27:39.719Z"
-  },
-  "15": {
-    "id": "15",
-    "design": 5,
-    "color": 5,
-    "style": 5,
-    "decision": "keep",
-    "why": "The design lacks distinctive elements, resulting in a generic, unremarkable aesthetic that fails to captivate or differentiate within the fl",
-    "updated_at": "2026-05-12T04:25:34.107Z"
-  },
-  "16": {
-    "id": "16",
-    "design": 5,
-    "color": 5,
-    "style": 5,
-    "decision": "reject",
-    "why": "The design lacks visual complexity and dynamic contrast, resulting in a flat, uninspired geometric pattern that fails to engage or different",
-    "updated_at": "2026-05-12T04:25:47.411Z"
-  },
-  "17": {
-    "id": "17",
-    "design": 7,
-    "color": 5,
-    "style": 5,
-    "decision": null,
-    "why": "",
-    "updated_at": "2026-05-12T04:25:49.289Z"
-  }
-}
\ No newline at end of file
+{}
\ No newline at end of file

← 5bdabe9 gamify: user votes + head-to-head polls + Elo + 5-variation  ·  back to Wallco Ai  ·  fix(wallco-ai/404): drop is_published filter so recovery row a8488e5 →