@mcptoolshop/style-dataset-lab 3.0.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -15
- package/CODE_OF_CONDUCT.md +9 -0
- package/CONTRIBUTING.md +71 -0
- package/README.md +46 -1
- package/SECURITY.md +6 -5
- package/bin/sdlab.js +281 -62
- package/lib/adapters/diffusers-lora.js +7 -2
- package/lib/adapters/generic-image-caption.js +6 -1
- package/lib/args.js +200 -13
- package/lib/batch-compiler.js +7 -3
- package/lib/batch-runs.js +100 -31
- package/lib/batch-sheet-render.js +5 -2
- package/lib/brief-compiler.js +38 -11
- package/lib/card.js +11 -4
- package/lib/comfyui.js +100 -6
- package/lib/config.js +68 -3
- package/lib/deprecation.js +1 -1
- package/lib/eval-pack.js +94 -4
- package/lib/eval-runs.js +42 -3
- package/lib/export.js +144 -34
- package/lib/implementation-packs.js +15 -1
- package/lib/log.js +41 -4
- package/lib/paths.js +41 -3
- package/lib/refine-briefs.js +16 -9
- package/lib/reingest-selected.js +14 -3
- package/lib/reingest.js +15 -1
- package/lib/run-summary.js +3 -2
- package/lib/runtime-runs.js +59 -9
- package/lib/selections.js +54 -2
- package/lib/snapshot.js +100 -7
- package/lib/split.js +175 -17
- package/lib/training-manifests.js +17 -3
- package/lib/training-packages.js +28 -14
- package/package.json +8 -2
- package/scripts/batch-generate.js +16 -7
- package/scripts/batch-sheet.js +3 -3
- package/scripts/batch-show.js +3 -3
- package/scripts/brief-compile.js +8 -8
- package/scripts/brief-show.js +4 -3
- package/scripts/canon-bind.js +7 -9
- package/scripts/card.js +22 -25
- package/scripts/compare.js +38 -33
- package/scripts/critique-show.js +3 -3
- package/scripts/critique.js +3 -3
- package/scripts/curate.js +91 -46
- package/scripts/doctor.js +3 -5
- package/scripts/eligibility.js +17 -14
- package/scripts/eval-pack.js +13 -11
- package/scripts/eval-run.js +30 -29
- package/scripts/export.js +27 -31
- package/scripts/generate-controlnet.js +31 -17
- package/scripts/generate-identity.js +37 -20
- package/scripts/generate-ipadapter.js +22 -16
- package/scripts/generate.js +68 -13
- package/scripts/implementation-pack.js +19 -14
- package/scripts/init.js +115 -17
- package/scripts/painterly.js +8 -10
- package/scripts/refine.js +3 -3
- package/scripts/reingest-selected.js +3 -3
- package/scripts/reingest.js +33 -20
- package/scripts/run-generate.js +4 -4
- package/scripts/run-list.js +3 -3
- package/scripts/run-show.js +3 -3
- package/scripts/select.js +5 -4
- package/scripts/selection-show.js +3 -3
- package/scripts/snapshot.js +22 -24
- package/scripts/split.js +26 -31
- package/scripts/training-manifest.js +29 -24
- package/scripts/training-package.js +24 -20
- package/scripts/training-profile.js +13 -8
- package/scripts/workflow-list.js +2 -2
- package/scripts/workflow-show.js +4 -3
- package/templates/domains/architecture/inputs/prompts/example-wave.json +32 -0
- package/templates/domains/architecture/terminology.json +10 -8
- package/templates/domains/character-design/inputs/prompts/example-wave.json +32 -0
- package/templates/domains/character-design/project.json +4 -2
- package/templates/domains/creature-design/inputs/prompts/example-wave.json +32 -0
- package/templates/domains/creature-design/project.json +4 -2
- package/templates/domains/creature-design/terminology.json +1 -0
- package/templates/domains/game-art/inputs/prompts/example-wave.json +37 -0
- package/templates/domains/game-art/project.json +4 -2
- package/templates/domains/vehicle-mech/inputs/prompts/example-wave.json +37 -0
- package/templates/domains/vehicle-mech/project.json +4 -2
- package/scripts/bulk-curate-wave2-5.js +0 -138
- package/scripts/bulk-curate-waves11-18.js +0 -413
- package/scripts/curate-wave25.js +0 -209
- package/scripts/migrate-records.js +0 -141
- package/templates/inputs/prompts/example-wave.json +0 -27
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"wave": "wave1",
|
|
3
|
+
"description": "Vehicle / mech — first wave. Subject IDs match this domain's lane id_patterns (ext_, cockpit_, component_, schematic_) so `sdlab generate` will route each candidate into the correct lane instead of default_lane.",
|
|
4
|
+
"defaults": {
|
|
5
|
+
"checkpoint": "dreamshaperXL_v21TurboDPMSDE.safetensors",
|
|
6
|
+
"lora": { "name": "classipeintxl_v21.safetensors", "weight": 1.0 },
|
|
7
|
+
"width": 1024,
|
|
8
|
+
"height": 1024,
|
|
9
|
+
"steps": 8,
|
|
10
|
+
"cfg": 2.0,
|
|
11
|
+
"sampler": "dpmpp_sde",
|
|
12
|
+
"scheduler": "karras",
|
|
13
|
+
"negative": "photorealistic, photograph, 3d render, smooth CG, sharp photo detail"
|
|
14
|
+
},
|
|
15
|
+
"subjects": [
|
|
16
|
+
{
|
|
17
|
+
"id": "ext_flagship",
|
|
18
|
+
"variations": 2,
|
|
19
|
+
"prompt": "oil painting, visible brushstrokes, [DESCRIBE YOUR VEHICLE — hull design, body panels, overall form language], painterly concept art, canvas grain"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "cockpit_flagship",
|
|
23
|
+
"variations": 2,
|
|
24
|
+
"prompt": "oil painting, visible brushstrokes, [DESCRIBE YOUR COCKPIT — bridge layout, cabin instruments, pilot seating], painterly concept art, canvas grain"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "component_engine",
|
|
28
|
+
"variations": 2,
|
|
29
|
+
"prompt": "oil painting, visible brushstrokes, [DESCRIBE A COMPONENT — engine, weapon, thruster, subsystem detail], painterly concept art, canvas grain"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "schematic_overview",
|
|
33
|
+
"variations": 2,
|
|
34
|
+
"prompt": "oil painting, visible brushstrokes, [DESCRIBE YOUR SCHEMATIC — technical diagram, orthographic breakdown, cross-section], painterly concept art, canvas grain"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
"domain": "vehicle-mech",
|
|
5
5
|
"version": "0.1.0",
|
|
6
6
|
"defaults": {
|
|
7
|
-
"checkpoint": "",
|
|
8
|
-
"loras": [
|
|
7
|
+
"checkpoint": "dreamshaperXL_v21TurboDPMSDE.safetensors",
|
|
8
|
+
"loras": [
|
|
9
|
+
{ "name": "classipeintxl_v21.safetensors", "weight": 1.0 }
|
|
10
|
+
],
|
|
9
11
|
"width": 1024,
|
|
10
12
|
"height": 1024,
|
|
11
13
|
"steps": 8,
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Bulk curation for waves 2-5.
|
|
5
|
-
* Applies rules-based initial curation, then individual overrides.
|
|
6
|
-
* Must still visually verify — this is a first pass, not final judgment.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { readFile, writeFile, rename, readdir, mkdir } from "node:fs/promises";
|
|
10
|
-
import { join } from "node:path";
|
|
11
|
-
|
|
12
|
-
const REPO_ROOT = new URL("..", import.meta.url).pathname.replace(/^\/([A-Z]:)/, "$1");
|
|
13
|
-
const GAME = process.argv.find((a, i) => process.argv[i - 1] === '--game') || 'star-freight';
|
|
14
|
-
const GAME_ROOT = join(REPO_ROOT, 'projects', GAME);
|
|
15
|
-
|
|
16
|
-
const DEFAULT_APPROVED_SCORES = {
|
|
17
|
-
silhouette_clarity: 0.8, palette_adherence: 0.8, material_fidelity: 0.8,
|
|
18
|
-
faction_read: 0.8, wear_level: 0.8, style_consistency: 0.7,
|
|
19
|
-
clothing_logic: 0.8, composition: 0.8,
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const REJECT_EXPLANATIONS = {
|
|
23
|
-
"REJECT2_fantasy_knight": { explanation: "Full medieval plate armor, heraldic tabard, broadsword and shield. Fantasy not sci-fi. Violates every art pillar.", failures: ["generic_scifi", "wrong_material"], scores: { silhouette_clarity: 0.8, palette_adherence: 0.2, material_fidelity: 0.4, faction_read: 0.0, wear_level: 0.3, style_consistency: 0.4, clothing_logic: 0.1, composition: 0.8 } },
|
|
24
|
-
"REJECT2_cyberpunk_f": { explanation: "Neon hair, glowing circuit tattoos, shiny PVC bodysuit, LED accessories. Cyberpunk nightclub not cargo bay. Violates COL-003, CLO-003.", failures: ["wrong_palette", "costume_not_clothes"], scores: { silhouette_clarity: 0.8, palette_adherence: 0.1, material_fidelity: 0.3, faction_read: 0.0, wear_level: 0.1, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.8 } },
|
|
25
|
-
"REJECT2_too_sexy_f": { explanation: "Skin-tight form-fitting uniform emphasizing figure, styled hair, makeup, high heels. Cosplay not clothing. Violates CLO-003, MAT-002.", failures: ["costume_not_clothes", "too_clean"], scores: { silhouette_clarity: 0.8, palette_adherence: 0.5, material_fidelity: 0.3, faction_read: 0.3, wear_level: 0.1, style_consistency: 0.4, clothing_logic: 0.2, composition: 0.8 } },
|
|
26
|
-
"REJECT2_warhammer_m": { explanation: "Bulky powered exoskeleton with imperial eagles, purity seals, gothic elements, chainsaw sword. Warhammer 40k power fantasy. Violates all five art pillars.", failures: ["generic_scifi", "too_heroic", "costume_not_clothes"], scores: { silhouette_clarity: 0.9, palette_adherence: 0.2, material_fidelity: 0.5, faction_read: 0.0, wear_level: 0.2, style_consistency: 0.4, clothing_logic: 0.1, composition: 0.8 } },
|
|
27
|
-
"REJECT3_veshan_cute": { explanation: "Cute baby reptilian with big round eyes, pastel skin, tiny adorable outfit. Mascot character not warrior culture. Violates faction identity completely.", failures: ["faction_unreadable", "costume_not_clothes"], scores: { silhouette_clarity: 0.7, palette_adherence: 0.2, material_fidelity: 0.3, faction_read: 0.1, wear_level: 0.1, style_consistency: 0.3, clothing_logic: 0.2, composition: 0.8 } },
|
|
28
|
-
"REJECT3_veshan_robot": { explanation: "Reptilian in sleek chrome powered armor covering every scale, glowing visor, jet thrusters. Mecha pilot not Veshan warrior. No forge marks, no imperfections. Violates MAT-001, CLO-002.", failures: ["generic_scifi", "wrong_material", "too_clean"], scores: { silhouette_clarity: 0.8, palette_adherence: 0.3, material_fidelity: 0.2, faction_read: 0.2, wear_level: 0.1, style_consistency: 0.5, clothing_logic: 0.2, composition: 0.8 } },
|
|
29
|
-
"REJECT3_generic_lizard": { explanation: "Generic lizard person in brown tunic. No crest ridge, no brow ridges, no tail, round eyes, smooth skin, human proportions. Human in lizard mask, not an alien species.", failures: ["faction_unreadable", "wrong_material"], scores: { silhouette_clarity: 0.7, palette_adherence: 0.4, material_fidelity: 0.3, faction_read: 0.1, wear_level: 0.5, style_consistency: 0.5, clothing_logic: 0.3, composition: 0.8 } },
|
|
30
|
-
"REJECT4_clean_pirate": { explanation: "Dashing pirate in pristine white shirt, embroidered vest, polished boots, jeweled rapier. Romance novel cover not lawless frontier. Violates MAT-002, CLO-003.", failures: ["too_clean", "costume_not_clothes"], scores: { silhouette_clarity: 0.8, palette_adherence: 0.3, material_fidelity: 0.3, faction_read: 0.2, wear_level: 0.1, style_consistency: 0.4, clothing_logic: 0.2, composition: 0.8 } },
|
|
31
|
-
"REJECT4_matching_gang": { explanation: "Perfectly matching black tactical gear — same brand, same condition, all pristine. Video game loadout not Sable Reach. Nothing mismatched, nothing salvaged, nothing stolen.", failures: ["too_clean", "generic_scifi"], scores: { silhouette_clarity: 0.8, palette_adherence: 0.4, material_fidelity: 0.5, faction_read: 0.1, wear_level: 0.2, style_consistency: 0.5, clothing_logic: 0.2, composition: 0.8 } },
|
|
32
|
-
"REJECT4_space_cowboy": { explanation: "Old west cowboy outfit in space — chaps, Stetson, plaid shirt, spurs. Genre costume at a sci-fi convention, not lived-in sci-fi. Violates CLO-003.", failures: ["costume_not_clothes", "faction_unreadable"], scores: { silhouette_clarity: 0.8, palette_adherence: 0.3, material_fidelity: 0.4, faction_read: 0.0, wear_level: 0.5, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.8 } },
|
|
33
|
-
"REJECT5_all_factions_salad": { explanation: "Designer outfit smoothly blending all faction aesthetics into one harmonious garment. Nothing is torn, stolen, or improvised. Violates every faction boundary rule.", failures: ["faction_unreadable", "too_clean"], scores: { silhouette_clarity: 0.8, palette_adherence: 0.3, material_fidelity: 0.5, faction_read: 0.1, wear_level: 0.3, style_consistency: 0.5, clothing_logic: 0.2, composition: 0.8 } },
|
|
34
|
-
"REJECT5_no_faction_generic": { explanation: "Plain grey jumpsuit with zero cultural markers, no patches, no tools, no wear. Default human in default outfit. Nothing to learn from this.", failures: ["faction_unreadable"], scores: { silhouette_clarity: 0.7, palette_adherence: 0.4, material_fidelity: 0.3, faction_read: 0.0, wear_level: 0.3, style_consistency: 0.5, clothing_logic: 0.2, composition: 0.8 } },
|
|
35
|
-
"REJECT5_luxury_scifi": { explanation: "Tailored suit, gold watch, polished shoes, groomed hair. Corporate luxury executive. Never loaded cargo, never fixed a reactor. Not working-class space.", failures: ["too_clean", "costume_not_clothes"], scores: { silhouette_clarity: 0.8, palette_adherence: 0.4, material_fidelity: 0.4, faction_read: 0.1, wear_level: 0.1, style_consistency: 0.5, clothing_logic: 0.2, composition: 0.8 } },
|
|
36
|
-
"REJECT6_fashion_model_f": { explanation: "Haute couture space-themed evening gown with crystals and high heels. Fashion runway not shipboard life. Violates every art pillar.", failures: ["costume_not_clothes", "too_clean"], scores: { silhouette_clarity: 0.8, palette_adherence: 0.1, material_fidelity: 0.2, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.0, composition: 0.8 } },
|
|
37
|
-
"REJECT6_steampunk_m": { explanation: "Victorian steampunk with top hat, brass goggles, gears and cogs, steam-powered prosthetic. Retro-futurism cosplay not lived-in sci-fi. Wrong aesthetic entirely.", failures: ["costume_not_clothes", "generic_scifi"], scores: { silhouette_clarity: 0.8, palette_adherence: 0.3, material_fidelity: 0.4, faction_read: 0.0, wear_level: 0.4, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.8 } },
|
|
38
|
-
"REJECT6_identical_twins": { explanation: "Two identical figures in matching pristine uniforms. Violates single character rule and too-clean rule. Looks like mannequins or clones.", failures: ["bad_composition", "too_clean"], scores: { silhouette_clarity: 0.5, palette_adherence: 0.6, material_fidelity: 0.5, faction_read: 0.5, wear_level: 0.1, style_consistency: 0.5, clothing_logic: 0.4, composition: 0.2 } },
|
|
39
|
-
"REJECT7_veshan_human_clothes": { explanation: "Veshan in Compact-style pressed uniform designed for human body. Fights against scale ridges and digitigrade legs. Wrong material vocabulary for species.", failures: ["wrong_material", "faction_unreadable"], scores: { silhouette_clarity: 0.7, palette_adherence: 0.5, material_fidelity: 0.2, faction_read: 0.2, wear_level: 0.6, style_consistency: 0.6, clothing_logic: 0.2, composition: 0.8 } },
|
|
40
|
-
"REJECT7_cute_dragon": { explanation: "Adorable small dragon with sparkly eyes, tiny wings, pink pastel scales, cute crown and cape with stars. Mascot toy not warrior civilization member.", failures: ["faction_unreadable", "costume_not_clothes"], scores: { silhouette_clarity: 0.7, palette_adherence: 0.1, material_fidelity: 0.2, faction_read: 0.0, wear_level: 0.1, style_consistency: 0.2, clothing_logic: 0.1, composition: 0.8 } },
|
|
41
|
-
"REJECT8_superhero_f": { explanation: "Glossy red and gold spandex bodysuit with cape, mask, power pose, stylized emblem. Superhero costume not clothing. Wrong genre entirely.", failures: ["costume_not_clothes", "generic_scifi"], scores: { silhouette_clarity: 0.8, palette_adherence: 0.1, material_fidelity: 0.2, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.2, clothing_logic: 0.0, composition: 0.7 } },
|
|
42
|
-
"REJECT8_zombified_m": { explanation: "Rotting grey skin, milky eyes, bloodied torn uniform. Horror zombie genre not lived-in sci-fi. Wrong genre.", failures: ["generic_scifi"], scores: { silhouette_clarity: 0.7, palette_adherence: 0.3, material_fidelity: 0.4, faction_read: 0.3, wear_level: 0.5, style_consistency: 0.3, clothing_logic: 0.3, composition: 0.7 } },
|
|
43
|
-
"REJECT9_invisible_m": { explanation: "Cloaking suit making the character transparent. Cannot judge style of something invisible. Science fiction special effect not costume.", failures: ["generic_scifi"], scores: { silhouette_clarity: 0.1, palette_adherence: 0.2, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.5 } },
|
|
44
|
-
"REJECT9_alien_xenomorph": { explanation: "Biomechanical Xenomorph creature from the Alien franchise. No clothing, existing IP not original design. Wrong in every way.", failures: ["generic_scifi", "faction_unreadable"], scores: { silhouette_clarity: 0.8, palette_adherence: 0.2, material_fidelity: 0.3, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.0, composition: 0.7 } },
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
async function main() {
|
|
48
|
-
const recordsDir = join(GAME_ROOT, "records");
|
|
49
|
-
const files = await readdir(recordsDir);
|
|
50
|
-
|
|
51
|
-
let approved = 0;
|
|
52
|
-
let rejected = 0;
|
|
53
|
-
let total = 0;
|
|
54
|
-
|
|
55
|
-
for (const file of files.filter(f => f.endsWith(".json")).sort()) {
|
|
56
|
-
const path = join(recordsDir, file);
|
|
57
|
-
const record = JSON.parse(await readFile(path, "utf-8"));
|
|
58
|
-
|
|
59
|
-
// Skip already curated
|
|
60
|
-
if (record.judgment) continue;
|
|
61
|
-
|
|
62
|
-
total++;
|
|
63
|
-
const id = record.id;
|
|
64
|
-
const baseId = id.replace(/_v[12]$/, "");
|
|
65
|
-
|
|
66
|
-
// Determine status
|
|
67
|
-
let status, explanation, failures = [], scores;
|
|
68
|
-
|
|
69
|
-
if (REJECT_EXPLANATIONS[baseId]) {
|
|
70
|
-
const rej = REJECT_EXPLANATIONS[baseId];
|
|
71
|
-
status = "rejected";
|
|
72
|
-
explanation = rej.explanation;
|
|
73
|
-
failures = rej.failures;
|
|
74
|
-
scores = rej.scores;
|
|
75
|
-
} else if (baseId.startsWith("BORDERLINE_")) {
|
|
76
|
-
status = "borderline";
|
|
77
|
-
explanation = `Almost on-style but fails in a subtle way that teaches nuance. See subject ID for specific issue.`;
|
|
78
|
-
scores = { silhouette_clarity: 0.7, palette_adherence: 0.65, material_fidelity: 0.65, faction_read: 0.6, wear_level: 0.6, style_consistency: 0.65, clothing_logic: 0.6, composition: 0.75 };
|
|
79
|
-
} else {
|
|
80
|
-
// Default approve with standard scores
|
|
81
|
-
status = "approved";
|
|
82
|
-
explanation = `On-style gritty space costume. Faction-appropriate material vocabulary and wear level. Reads as a working person in a spacefaring civilization.`;
|
|
83
|
-
scores = { ...DEFAULT_APPROVED_SCORES };
|
|
84
|
-
|
|
85
|
-
// Adjust explanation by faction prefix
|
|
86
|
-
if (id.startsWith("c2_")) {
|
|
87
|
-
explanation = `Compact faction crew. Regulation shipboard clothing with appropriate wear and institutional identity markers. Muted palette, functional design.`;
|
|
88
|
-
} else if (id.startsWith("v3_")) {
|
|
89
|
-
explanation = `Veshan faction. Forged material vocabulary with overlapping scales, dark bronze plate, leather underpadding. Martial culture expressed through gear.`;
|
|
90
|
-
scores.material_fidelity = 0.85;
|
|
91
|
-
} else if (id.startsWith("sr4_")) {
|
|
92
|
-
explanation = `Sable Reach outlaw. Salvaged, stolen, and improvised gear. Nothing matches, nothing is new, everything tells a survival story.`;
|
|
93
|
-
scores.faction_read = 0.85;
|
|
94
|
-
scores.wear_level = 0.9;
|
|
95
|
-
} else if (id.startsWith("cf_")) {
|
|
96
|
-
explanation = `Cross-faction comparison subject. Faction-appropriate costume for the specified role, useful for teaching same-role-different-faction visual discrimination.`;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Move image
|
|
101
|
-
const oldPath = join(GAME_ROOT, record.asset_path);
|
|
102
|
-
const newDir = `outputs/${status}`;
|
|
103
|
-
const newPath = `${newDir}/${id}.png`;
|
|
104
|
-
await mkdir(join(GAME_ROOT, newDir), { recursive: true });
|
|
105
|
-
|
|
106
|
-
try {
|
|
107
|
-
await rename(oldPath, join(GAME_ROOT, newPath));
|
|
108
|
-
} catch {
|
|
109
|
-
console.log(` skip ${id} — image not found at ${record.asset_path}`);
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Update record
|
|
114
|
-
record.asset_path = newPath;
|
|
115
|
-
record.judgment = {
|
|
116
|
-
status,
|
|
117
|
-
reviewer: "bulk_curate_v1",
|
|
118
|
-
reviewed_at: new Date().toISOString(),
|
|
119
|
-
explanation,
|
|
120
|
-
criteria_scores: scores,
|
|
121
|
-
failure_modes: failures,
|
|
122
|
-
improvement_notes: null,
|
|
123
|
-
confidence: status === "rejected" ? 0.95 : 0.75, // bulk approvals get lower confidence
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
await writeFile(path, JSON.stringify(record, null, 2));
|
|
127
|
-
|
|
128
|
-
if (status === "approved") approved++;
|
|
129
|
-
else rejected++;
|
|
130
|
-
|
|
131
|
-
const icon = status === "approved" ? "\x1b[32m✓\x1b[0m" : "\x1b[31m✗\x1b[0m";
|
|
132
|
-
console.log(`${icon} ${id} → ${status}`);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
console.log(`\n${total} curated: ${approved} approved, ${rejected} rejected`);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
main().catch(console.error);
|
|
@@ -1,413 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Bulk curation for waves 11-18 (expanded categories).
|
|
4
|
-
*
|
|
5
|
-
* Strategy:
|
|
6
|
-
* - REJECT* subjects → rejected with specific explanations
|
|
7
|
-
* - All other subjects → approved with category-appropriate scores
|
|
8
|
-
* - Score profiles differ by category (ships, interiors, equipment, etc.)
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* node scripts/bulk-curate-waves11-18.js
|
|
12
|
-
* node scripts/bulk-curate-waves11-18.js --dry-run
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { readFileSync, writeFileSync, readdirSync, renameSync, existsSync, mkdirSync } from 'fs';
|
|
16
|
-
import { join, basename } from 'path';
|
|
17
|
-
|
|
18
|
-
const REPO_ROOT = new URL("..", import.meta.url).pathname.replace(/^\/([A-Z]:)/, "$1");
|
|
19
|
-
const GAME = process.argv.find((a, i) => process.argv[i - 1] === '--game') || 'star-freight';
|
|
20
|
-
const GAME_ROOT = join(REPO_ROOT, 'projects', GAME);
|
|
21
|
-
|
|
22
|
-
const RECORDS_DIR = join(GAME_ROOT, 'records');
|
|
23
|
-
const CANDIDATES_DIR = join(GAME_ROOT, 'outputs', 'candidates');
|
|
24
|
-
const APPROVED_DIR = join(GAME_ROOT, 'outputs', 'approved');
|
|
25
|
-
const REJECTED_DIR = join(GAME_ROOT, 'outputs', 'rejected');
|
|
26
|
-
const DRY_RUN = process.argv.includes('--dry-run');
|
|
27
|
-
|
|
28
|
-
// Ensure output dirs exist
|
|
29
|
-
for (const dir of [APPROVED_DIR, REJECTED_DIR]) {
|
|
30
|
-
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// ─── Rejection explanations ──────────────────────────────────────────
|
|
34
|
-
|
|
35
|
-
const REJECT_EXPLANATIONS = {
|
|
36
|
-
// Wave 11 rejects
|
|
37
|
-
REJECT11_star_destroyer: {
|
|
38
|
-
explanation: "Massive gleaming triangular warship — Imperial Star Destroyer aesthetic. Too clean, too military-imperial, wrong power scale for gritty space.",
|
|
39
|
-
failures: ["generic_scifi", "too_clean"],
|
|
40
|
-
scores: { silhouette_clarity: 0.9, palette_adherence: 0.2, material_fidelity: 0.2, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.4, clothing_logic: 0.3, composition: 0.8 }
|
|
41
|
-
},
|
|
42
|
-
REJECT11_luxury_yacht: {
|
|
43
|
-
explanation: "Sleek luxury spacecraft with chrome and panoramic windows. Rich person's toy, not working vehicle. Violates every grit principle.",
|
|
44
|
-
failures: ["too_clean", "costume_not_clothes"],
|
|
45
|
-
scores: { silhouette_clarity: 0.7, palette_adherence: 0.1, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.7 }
|
|
46
|
-
},
|
|
47
|
-
REJECT11_anime_ship: {
|
|
48
|
-
explanation: "Colorful exaggerated spacecraft with anime proportions and racing stripes. Wrong aesthetic entirely — cel-shaded toy, not working vessel.",
|
|
49
|
-
failures: ["anime_style", "wrong_palette"],
|
|
50
|
-
scores: { silhouette_clarity: 0.6, palette_adherence: 0.1, material_fidelity: 0.2, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.1, clothing_logic: 0.2, composition: 0.6 }
|
|
51
|
-
},
|
|
52
|
-
// Wave 12 rejects
|
|
53
|
-
REJECT12_star_trek_bridge: {
|
|
54
|
-
explanation: "Sleek bright bridge with holographic displays and pristine surfaces. Star Trek aesthetic — too clean, too advanced, too comfortable.",
|
|
55
|
-
failures: ["generic_scifi", "too_clean"],
|
|
56
|
-
scores: { silhouette_clarity: 0.7, palette_adherence: 0.2, material_fidelity: 0.2, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.2, composition: 0.7 }
|
|
57
|
-
},
|
|
58
|
-
REJECT12_luxury_cabin: {
|
|
59
|
-
explanation: "Spacious luxury cabin with king bed, silk sheets, panoramic viewport. Five-star hotel in space, not crew quarters.",
|
|
60
|
-
failures: ["too_clean", "costume_not_clothes"],
|
|
61
|
-
scores: { silhouette_clarity: 0.5, palette_adherence: 0.1, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.2, clothing_logic: 0.1, composition: 0.6 }
|
|
62
|
-
},
|
|
63
|
-
REJECT12_holodeck: {
|
|
64
|
-
explanation: "Empty room with glowing grid lines — holodeck concept. Pure Star Trek, no grounded reality, no lived-in quality.",
|
|
65
|
-
failures: ["generic_scifi"],
|
|
66
|
-
scores: { silhouette_clarity: 0.3, palette_adherence: 0.2, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.2, clothing_logic: 0.1, composition: 0.5 }
|
|
67
|
-
},
|
|
68
|
-
// Wave 13 rejects
|
|
69
|
-
REJECT13_clean_promenade: {
|
|
70
|
-
explanation: "Pristine shopping promenade with luxury storefronts and gleaming floors. High-end mall in space, not working station.",
|
|
71
|
-
failures: ["too_clean", "generic_scifi"],
|
|
72
|
-
scores: { silhouette_clarity: 0.6, palette_adherence: 0.1, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.7 }
|
|
73
|
-
},
|
|
74
|
-
REJECT13_resort_station: {
|
|
75
|
-
explanation: "Luxury resort with infinity pool and spa. Tourist brochure for space, not gritty lived-in station.",
|
|
76
|
-
failures: ["too_clean", "costume_not_clothes"],
|
|
77
|
-
scores: { silhouette_clarity: 0.5, palette_adherence: 0.1, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.2, clothing_logic: 0.1, composition: 0.6 }
|
|
78
|
-
},
|
|
79
|
-
REJECT13_anime_mall: {
|
|
80
|
-
explanation: "Colorful station with neon signs and cute mascots. Anime space mall aesthetic — wrong style entirely.",
|
|
81
|
-
failures: ["anime_style", "wrong_palette"],
|
|
82
|
-
scores: { silhouette_clarity: 0.5, palette_adherence: 0.1, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.1, clothing_logic: 0.1, composition: 0.5 }
|
|
83
|
-
},
|
|
84
|
-
// Wave 14 rejects
|
|
85
|
-
REJECT14_lightsaber: {
|
|
86
|
-
explanation: "Elegant glowing energy sword — lightsaber aesthetic. Star Wars iconic weapon, not grounded faction equipment.",
|
|
87
|
-
failures: ["generic_scifi"],
|
|
88
|
-
scores: { silhouette_clarity: 0.8, palette_adherence: 0.2, material_fidelity: 0.2, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.2, composition: 0.8 }
|
|
89
|
-
},
|
|
90
|
-
REJECT14_anime_weapon: {
|
|
91
|
-
explanation: "Oversized fantasy weapon with glowing runes — anime aesthetic. Impossible proportions, wrong genre.",
|
|
92
|
-
failures: ["anime_style", "generic_scifi"],
|
|
93
|
-
scores: { silhouette_clarity: 0.6, palette_adherence: 0.1, material_fidelity: 0.2, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.1, clothing_logic: 0.1, composition: 0.6 }
|
|
94
|
-
},
|
|
95
|
-
REJECT14_chrome_gun: {
|
|
96
|
-
explanation: "Perfectly polished chrome handgun with LED accents. Product advertisement, no wear or history, not a working weapon.",
|
|
97
|
-
failures: ["too_clean"],
|
|
98
|
-
scores: { silhouette_clarity: 0.8, palette_adherence: 0.2, material_fidelity: 0.3, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.4, clothing_logic: 0.2, composition: 0.8 }
|
|
99
|
-
},
|
|
100
|
-
// Wave 15 rejects
|
|
101
|
-
REJECT15_modern_ui: {
|
|
102
|
-
explanation: "Flat Material Design UI mockup. Contemporary smartphone aesthetic, not sci-fi, not painterly.",
|
|
103
|
-
failures: ["generic_scifi"],
|
|
104
|
-
scores: { silhouette_clarity: 0.4, palette_adherence: 0.2, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.1, clothing_logic: 0.1, composition: 0.5 }
|
|
105
|
-
},
|
|
106
|
-
REJECT15_neon_sign: {
|
|
107
|
-
explanation: "Vivid cyberpunk neon tubes. Too bright, too colorful, too urban — nightclub not spaceship.",
|
|
108
|
-
failures: ["wrong_palette", "generic_scifi"],
|
|
109
|
-
scores: { silhouette_clarity: 0.6, palette_adherence: 0.1, material_fidelity: 0.2, faction_read: 0.0, wear_level: 0.1, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.6 }
|
|
110
|
-
},
|
|
111
|
-
REJECT15_fantasy_runes: {
|
|
112
|
-
explanation: "Glowing magical runes on stone — Lord of the Rings aesthetic. Fantasy, not sci-fi. Wrong genre entirely.",
|
|
113
|
-
failures: ["generic_scifi"],
|
|
114
|
-
scores: { silhouette_clarity: 0.5, palette_adherence: 0.1, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.2, style_consistency: 0.2, clothing_logic: 0.1, composition: 0.5 }
|
|
115
|
-
},
|
|
116
|
-
// Wave 16 rejects
|
|
117
|
-
REJECT16_bright_clean: {
|
|
118
|
-
explanation: "Brightly lit pristine white corridor — modern office aesthetic. Too clean, too comfortable, no grit.",
|
|
119
|
-
failures: ["too_clean"],
|
|
120
|
-
scores: { silhouette_clarity: 0.5, palette_adherence: 0.1, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.6 }
|
|
121
|
-
},
|
|
122
|
-
REJECT16_sunset_beauty: {
|
|
123
|
-
explanation: "Beautiful golden sunset through panoramic window. Tourist brochure lighting, romantic and scenic, not gritty or tense.",
|
|
124
|
-
failures: ["too_clean", "generic_scifi"],
|
|
125
|
-
scores: { silhouette_clarity: 0.4, palette_adherence: 0.2, material_fidelity: 0.2, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.5 }
|
|
126
|
-
},
|
|
127
|
-
// Wave 17 rejects
|
|
128
|
-
REJECT17_sleek_hovervehicle: {
|
|
129
|
-
explanation: "Chrome luxury hover transport — concept car aesthetic. No dirt, no wear, wrong power fantasy.",
|
|
130
|
-
failures: ["too_clean", "generic_scifi"],
|
|
131
|
-
scores: { silhouette_clarity: 0.7, palette_adherence: 0.1, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.7 }
|
|
132
|
-
},
|
|
133
|
-
REJECT17_military_tank: {
|
|
134
|
-
explanation: "Modern Earth military tank. Wrong genre — ground combat vehicle from present day, not lived-in sci-fi.",
|
|
135
|
-
failures: ["generic_scifi"],
|
|
136
|
-
scores: { silhouette_clarity: 0.8, palette_adherence: 0.3, material_fidelity: 0.4, faction_read: 0.0, wear_level: 0.5, style_consistency: 0.4, clothing_logic: 0.2, composition: 0.7 }
|
|
137
|
-
},
|
|
138
|
-
REJECT17_golden_crate: {
|
|
139
|
-
explanation: "Ornate golden treasure chest with jewels. Fantasy RPG loot, not cargo container. Wrong genre.",
|
|
140
|
-
failures: ["generic_scifi", "wrong_palette"],
|
|
141
|
-
scores: { silhouette_clarity: 0.7, palette_adherence: 0.0, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.2, clothing_logic: 0.1, composition: 0.7 }
|
|
142
|
-
},
|
|
143
|
-
// Wave 18 rejects
|
|
144
|
-
REJECT18_cute_pet: {
|
|
145
|
-
explanation: "Adorable fluffy alien pet with sparkly eyes. Kawaii mascot, not ship vermin or working animal. Too cute for gritty space.",
|
|
146
|
-
failures: ["anime_style", "generic_scifi"],
|
|
147
|
-
scores: { silhouette_clarity: 0.6, palette_adherence: 0.1, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.1, clothing_logic: 0.1, composition: 0.7 }
|
|
148
|
-
},
|
|
149
|
-
REJECT18_fantasy_feast: {
|
|
150
|
-
explanation: "Medieval fantasy banquet with golden platters and crystal goblets. King's feast, not crew rations. Wrong genre.",
|
|
151
|
-
failures: ["generic_scifi", "too_clean"],
|
|
152
|
-
scores: { silhouette_clarity: 0.5, palette_adherence: 0.1, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.2, clothing_logic: 0.1, composition: 0.6 }
|
|
153
|
-
},
|
|
154
|
-
REJECT18_gem_artifact: {
|
|
155
|
-
explanation: "Glowing magical gemstone in golden setting with runes. Fantasy RPG artifact, not sci-fi equipment. Wrong genre.",
|
|
156
|
-
failures: ["generic_scifi", "wrong_palette"],
|
|
157
|
-
scores: { silhouette_clarity: 0.6, palette_adherence: 0.0, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.2, clothing_logic: 0.1, composition: 0.7 }
|
|
158
|
-
},
|
|
159
|
-
// Wave 19 rejects
|
|
160
|
-
REJECT19_fantasy_castle: {
|
|
161
|
-
explanation: "Medieval fantasy castle with spires and buttresses. Wrong genre — Lord of the Rings, not lived-in sci-fi.",
|
|
162
|
-
failures: ["generic_scifi"],
|
|
163
|
-
scores: { silhouette_clarity: 0.7, palette_adherence: 0.2, material_fidelity: 0.3, faction_read: 0.0, wear_level: 0.3, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.7 }
|
|
164
|
-
},
|
|
165
|
-
REJECT19_modern_office: {
|
|
166
|
-
explanation: "Contemporary office interior with glass partitions and ergonomic chairs. Modern Earth, not sci-fi, not gritty.",
|
|
167
|
-
failures: ["generic_scifi", "too_clean"],
|
|
168
|
-
scores: { silhouette_clarity: 0.5, palette_adherence: 0.1, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.6 }
|
|
169
|
-
},
|
|
170
|
-
REJECT19_art_nouveau: {
|
|
171
|
-
explanation: "Art Nouveau building with flowing organic curves and decorative ironwork. Beautiful and delicate — too pretty for any gritty space faction.",
|
|
172
|
-
failures: ["too_clean", "costume_not_clothes"],
|
|
173
|
-
scores: { silhouette_clarity: 0.6, palette_adherence: 0.2, material_fidelity: 0.2, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.7 }
|
|
174
|
-
},
|
|
175
|
-
// Wave 20 rejects
|
|
176
|
-
REJECT20_luxury_item: {
|
|
177
|
-
explanation: "Chrome designer coffee machine with LED accents. Luxury kitchen showroom, not a working ship's galley.",
|
|
178
|
-
failures: ["too_clean", "generic_scifi"],
|
|
179
|
-
scores: { silhouette_clarity: 0.7, palette_adherence: 0.1, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.7 }
|
|
180
|
-
},
|
|
181
|
-
REJECT20_modern_gadget: {
|
|
182
|
-
explanation: "Pristine modern smartphone-like device. Contemporary Apple aesthetic — too clean, too now, wrong era.",
|
|
183
|
-
failures: ["too_clean", "generic_scifi"],
|
|
184
|
-
scores: { silhouette_clarity: 0.6, palette_adherence: 0.1, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.2, clothing_logic: 0.1, composition: 0.7 }
|
|
185
|
-
},
|
|
186
|
-
// Wave 21 rejects
|
|
187
|
-
REJECT21_paradise_planet: {
|
|
188
|
-
explanation: "Beautiful alien paradise with crystal waterfalls and twin suns. Tourist brochure, not gritty frontier.",
|
|
189
|
-
failures: ["too_clean", "generic_scifi"],
|
|
190
|
-
scores: { silhouette_clarity: 0.4, palette_adherence: 0.1, material_fidelity: 0.2, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.5 }
|
|
191
|
-
},
|
|
192
|
-
REJECT21_clean_colony: {
|
|
193
|
-
explanation: "Pristine futuristic colony with gleaming white domes. Utopian settlement — the brochure, not the reality.",
|
|
194
|
-
failures: ["too_clean"],
|
|
195
|
-
scores: { silhouette_clarity: 0.5, palette_adherence: 0.1, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.6 }
|
|
196
|
-
},
|
|
197
|
-
// Wave 22 rejects
|
|
198
|
-
REJECT22_clean_surface: {
|
|
199
|
-
explanation: "Factory-new brushed aluminum with even satin finish. No wear, no history, showroom quality.",
|
|
200
|
-
failures: ["too_clean"],
|
|
201
|
-
scores: { silhouette_clarity: 0.3, palette_adherence: 0.2, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.5 }
|
|
202
|
-
},
|
|
203
|
-
REJECT22_ornate_surface: {
|
|
204
|
-
explanation: "Gold-leafed surface with filigree and gemstone inlays. Luxury craftsmanship, wrong for any working environment.",
|
|
205
|
-
failures: ["too_clean", "wrong_palette"],
|
|
206
|
-
scores: { silhouette_clarity: 0.5, palette_adherence: 0.0, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.2, clothing_logic: 0.1, composition: 0.6 }
|
|
207
|
-
},
|
|
208
|
-
// Wave 23 rejects
|
|
209
|
-
REJECT23_rubber_suit_alien: {
|
|
210
|
-
explanation: "Humanoid alien that is clearly a human in makeup. Star Trek rubber-forehead aesthetic. Human body plan with decorative ridges. Not truly alien.",
|
|
211
|
-
failures: ["generic_scifi"],
|
|
212
|
-
scores: { silhouette_clarity: 0.5, palette_adherence: 0.3, material_fidelity: 0.3, faction_read: 0.1, wear_level: 0.3, style_consistency: 0.4, clothing_logic: 0.3, composition: 0.7 }
|
|
213
|
-
},
|
|
214
|
-
REJECT23_cute_alien: {
|
|
215
|
-
explanation: "Adorable big-eyed alien with pastel colors and baby proportions. Kawaii mascot designed to sell toys, not inhabit a gritty universe.",
|
|
216
|
-
failures: ["anime_style", "generic_scifi"],
|
|
217
|
-
scores: { silhouette_clarity: 0.6, palette_adherence: 0.1, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.1, clothing_logic: 0.1, composition: 0.7 }
|
|
218
|
-
},
|
|
219
|
-
REJECT24_catalog_interior: {
|
|
220
|
-
explanation: "IKEA-style staged living space with coordinated furniture and throw pillows. Contemporary lifestyle catalog, not a working ship or station.",
|
|
221
|
-
failures: ["too_clean", "generic_scifi"],
|
|
222
|
-
scores: { silhouette_clarity: 0.5, palette_adherence: 0.1, material_fidelity: 0.1, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.6 }
|
|
223
|
-
},
|
|
224
|
-
REJECT24_museum_clean: {
|
|
225
|
-
explanation: "Pristine museum exhibition with spotlighting and polished floors. Everything preserved and untouchable — the opposite of lived-in.",
|
|
226
|
-
failures: ["too_clean"],
|
|
227
|
-
scores: { silhouette_clarity: 0.5, palette_adherence: 0.2, material_fidelity: 0.2, faction_read: 0.0, wear_level: 0.0, style_consistency: 0.3, clothing_logic: 0.1, composition: 0.6 }
|
|
228
|
-
},
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
// ─── Category-specific score profiles ────────────────────────────────
|
|
232
|
-
|
|
233
|
-
const CATEGORY_SCORES = {
|
|
234
|
-
ship_ext: {
|
|
235
|
-
explanation: "Ship exterior with faction-appropriate hull design, wear, and construction.",
|
|
236
|
-
scores: { silhouette_clarity: 0.85, palette_adherence: 0.8, material_fidelity: 0.85, faction_read: 0.8, wear_level: 0.8, style_consistency: 0.7, clothing_logic: 0.8, composition: 0.85 }
|
|
237
|
-
},
|
|
238
|
-
int: {
|
|
239
|
-
explanation: "Ship interior with lived-in detail, faction-specific design language, and atmospheric lighting.",
|
|
240
|
-
scores: { silhouette_clarity: 0.75, palette_adherence: 0.8, material_fidelity: 0.85, faction_read: 0.8, wear_level: 0.85, style_consistency: 0.7, clothing_logic: 0.8, composition: 0.8 }
|
|
241
|
-
},
|
|
242
|
-
stn: {
|
|
243
|
-
explanation: "Station/port environment with gritty atmosphere, faction presence, and lived-in texture.",
|
|
244
|
-
scores: { silhouette_clarity: 0.75, palette_adherence: 0.8, material_fidelity: 0.8, faction_read: 0.75, wear_level: 0.85, style_consistency: 0.7, clothing_logic: 0.75, composition: 0.8 }
|
|
245
|
-
},
|
|
246
|
-
eqp: {
|
|
247
|
-
explanation: "Equipment/weapon with faction-specific design language, wear marks, and functional design.",
|
|
248
|
-
scores: { silhouette_clarity: 0.85, palette_adherence: 0.8, material_fidelity: 0.85, faction_read: 0.85, wear_level: 0.8, style_consistency: 0.7, clothing_logic: 0.85, composition: 0.85 }
|
|
249
|
-
},
|
|
250
|
-
prop: {
|
|
251
|
-
explanation: "Environmental prop with faction identity or universal grit, showing use and history.",
|
|
252
|
-
scores: { silhouette_clarity: 0.8, palette_adherence: 0.75, material_fidelity: 0.8, faction_read: 0.7, wear_level: 0.8, style_consistency: 0.7, clothing_logic: 0.75, composition: 0.85 }
|
|
253
|
-
},
|
|
254
|
-
sign: {
|
|
255
|
-
explanation: "Signage/UI/logo with faction-specific graphic design, appropriate weathering.",
|
|
256
|
-
scores: { silhouette_clarity: 0.85, palette_adherence: 0.85, material_fidelity: 0.8, faction_read: 0.85, wear_level: 0.75, style_consistency: 0.7, clothing_logic: 0.8, composition: 0.85 }
|
|
257
|
-
},
|
|
258
|
-
mood: {
|
|
259
|
-
explanation: "Lighting/mood study with strong atmospheric character appropriate to gritty space.",
|
|
260
|
-
scores: { silhouette_clarity: 0.7, palette_adherence: 0.85, material_fidelity: 0.8, faction_read: 0.6, wear_level: 0.85, style_consistency: 0.75, clothing_logic: 0.7, composition: 0.8 }
|
|
261
|
-
},
|
|
262
|
-
cargo: {
|
|
263
|
-
explanation: "Cargo/container with faction-specific construction, labeling, and wear.",
|
|
264
|
-
scores: { silhouette_clarity: 0.8, palette_adherence: 0.8, material_fidelity: 0.85, faction_read: 0.75, wear_level: 0.8, style_consistency: 0.7, clothing_logic: 0.8, composition: 0.85 }
|
|
265
|
-
},
|
|
266
|
-
ind: {
|
|
267
|
-
explanation: "Industrial scene with working-class space atmosphere, heavy equipment, grime.",
|
|
268
|
-
scores: { silhouette_clarity: 0.7, palette_adherence: 0.8, material_fidelity: 0.85, faction_read: 0.7, wear_level: 0.9, style_consistency: 0.7, clothing_logic: 0.75, composition: 0.8 }
|
|
269
|
-
},
|
|
270
|
-
veh: {
|
|
271
|
-
explanation: "Ground vehicle with utilitarian design, wear, and faction-appropriate construction.",
|
|
272
|
-
scores: { silhouette_clarity: 0.8, palette_adherence: 0.8, material_fidelity: 0.8, faction_read: 0.75, wear_level: 0.8, style_consistency: 0.7, clothing_logic: 0.8, composition: 0.85 }
|
|
273
|
-
},
|
|
274
|
-
food: {
|
|
275
|
-
explanation: "Food/drink item showing faction food culture, appropriate presentation, lived-in quality.",
|
|
276
|
-
scores: { silhouette_clarity: 0.75, palette_adherence: 0.75, material_fidelity: 0.8, faction_read: 0.7, wear_level: 0.75, style_consistency: 0.7, clothing_logic: 0.7, composition: 0.85 }
|
|
277
|
-
},
|
|
278
|
-
artifact: {
|
|
279
|
-
explanation: "Cultural artifact with deep faction identity, appropriate materials and aging.",
|
|
280
|
-
scores: { silhouette_clarity: 0.8, palette_adherence: 0.85, material_fidelity: 0.85, faction_read: 0.9, wear_level: 0.8, style_consistency: 0.7, clothing_logic: 0.85, composition: 0.85 }
|
|
281
|
-
},
|
|
282
|
-
creature: {
|
|
283
|
-
explanation: "Creature/animal fitting the gritty space universe — working animal, vermin, or alien fauna.",
|
|
284
|
-
scores: { silhouette_clarity: 0.8, palette_adherence: 0.75, material_fidelity: 0.8, faction_read: 0.6, wear_level: 0.7, style_consistency: 0.7, clothing_logic: 0.7, composition: 0.85 }
|
|
285
|
-
},
|
|
286
|
-
arch: {
|
|
287
|
-
explanation: "Faction architecture with species-appropriate ergonomics, material vocabulary, and lived-in detail.",
|
|
288
|
-
scores: { silhouette_clarity: 0.8, palette_adherence: 0.8, material_fidelity: 0.85, faction_read: 0.85, wear_level: 0.85, style_consistency: 0.7, clothing_logic: 0.8, composition: 0.8 }
|
|
289
|
-
},
|
|
290
|
-
env: {
|
|
291
|
-
explanation: "Planetary/environmental scene with functional gritty atmosphere, faction presence or universal frontier quality.",
|
|
292
|
-
scores: { silhouette_clarity: 0.75, palette_adherence: 0.8, material_fidelity: 0.8, faction_read: 0.7, wear_level: 0.85, style_consistency: 0.7, clothing_logic: 0.75, composition: 0.8 }
|
|
293
|
-
},
|
|
294
|
-
surf: {
|
|
295
|
-
explanation: "Surface texture/damage study showing the visual vocabulary of wear that defines gritty space.",
|
|
296
|
-
scores: { silhouette_clarity: 0.7, palette_adherence: 0.8, material_fidelity: 0.9, faction_read: 0.7, wear_level: 0.9, style_consistency: 0.7, clothing_logic: 0.75, composition: 0.8 }
|
|
297
|
-
},
|
|
298
|
-
life: {
|
|
299
|
-
explanation: "Alien species cultural moment — daily life, ceremony, or cross-species interaction that reveals who they are as people.",
|
|
300
|
-
scores: { silhouette_clarity: 0.8, palette_adherence: 0.8, material_fidelity: 0.85, faction_read: 0.85, wear_level: 0.8, style_consistency: 0.7, clothing_logic: 0.8, composition: 0.8 }
|
|
301
|
-
},
|
|
302
|
-
lived: {
|
|
303
|
-
explanation: "Lived-in detail — domestic objects in industrial spaces, paper ephemera, mundane commercial spaces, weathering progression, fabric on machinery. The details that make a universe breathe.",
|
|
304
|
-
scores: { silhouette_clarity: 0.75, palette_adherence: 0.8, material_fidelity: 0.85, faction_read: 0.65, wear_level: 0.9, style_consistency: 0.7, clothing_logic: 0.75, composition: 0.8 }
|
|
305
|
-
},
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
function detectCategory(id) {
|
|
309
|
-
if (/^ship_ext_/.test(id)) return 'ship_ext';
|
|
310
|
-
if (/^int_/.test(id)) return 'int';
|
|
311
|
-
if (/^stn_/.test(id)) return 'stn';
|
|
312
|
-
if (/^eqp_/.test(id)) return 'eqp';
|
|
313
|
-
if (/^prop_/.test(id)) return 'prop';
|
|
314
|
-
if (/^sign_/.test(id)) return 'sign';
|
|
315
|
-
if (/^mood_/.test(id)) return 'mood';
|
|
316
|
-
if (/^cargo_/.test(id)) return 'cargo';
|
|
317
|
-
if (/^ind_/.test(id)) return 'ind';
|
|
318
|
-
if (/^veh_/.test(id)) return 'veh';
|
|
319
|
-
if (/^food_/.test(id)) return 'food';
|
|
320
|
-
if (/^artifact_/.test(id)) return 'artifact';
|
|
321
|
-
if (/^creature_/.test(id)) return 'creature';
|
|
322
|
-
if (/^arch_/.test(id)) return 'arch';
|
|
323
|
-
if (/^env_/.test(id)) return 'env';
|
|
324
|
-
if (/^surf_/.test(id)) return 'surf';
|
|
325
|
-
if (/^life_/.test(id)) return 'life';
|
|
326
|
-
if (/^lived_/.test(id)) return 'lived';
|
|
327
|
-
return null;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// ─── Main ────────────────────────────────────────────────────────────
|
|
331
|
-
|
|
332
|
-
const newRecordPattern = /^(ship_ext_|int_|stn_|eqp_|prop_|sign_|mood_|cargo_|ind_|veh_|food_|artifact_|creature_|arch_|env_|surf_|life_|lived_|REJECT1[1-9]|REJECT2[0-9])/;
|
|
333
|
-
const files = readdirSync(RECORDS_DIR)
|
|
334
|
-
.filter(f => f.endsWith('.json') && newRecordPattern.test(f));
|
|
335
|
-
|
|
336
|
-
let approved = 0, rejected = 0, skipped = 0;
|
|
337
|
-
|
|
338
|
-
for (const file of files) {
|
|
339
|
-
const path = join(RECORDS_DIR, file);
|
|
340
|
-
const record = JSON.parse(readFileSync(path, 'utf-8'));
|
|
341
|
-
|
|
342
|
-
// Skip already curated
|
|
343
|
-
if (record.judgment && record.judgment.status) {
|
|
344
|
-
skipped++;
|
|
345
|
-
continue;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
const id = record.id;
|
|
349
|
-
const baseId = id.replace(/_v[12]$/, '');
|
|
350
|
-
const isReject = /^REJECT/.test(id);
|
|
351
|
-
const imgFile = `${id}.png`;
|
|
352
|
-
const srcPath = join(CANDIDATES_DIR, imgFile);
|
|
353
|
-
|
|
354
|
-
if (isReject) {
|
|
355
|
-
// Find matching reject explanation
|
|
356
|
-
const rejectInfo = REJECT_EXPLANATIONS[baseId];
|
|
357
|
-
if (!rejectInfo) {
|
|
358
|
-
console.log(` SKIP ${id} — no reject explanation found for ${baseId}`);
|
|
359
|
-
skipped++;
|
|
360
|
-
continue;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
record.judgment = {
|
|
364
|
-
status: 'rejected',
|
|
365
|
-
reviewer: 'bulk_curate_v2',
|
|
366
|
-
reviewed_at: new Date().toISOString(),
|
|
367
|
-
explanation: rejectInfo.explanation,
|
|
368
|
-
criteria_scores: { ...rejectInfo.scores },
|
|
369
|
-
failure_modes: [...rejectInfo.failures],
|
|
370
|
-
improvement_notes: null,
|
|
371
|
-
confidence: 0.95,
|
|
372
|
-
};
|
|
373
|
-
record.asset_path = `outputs/rejected/${imgFile}`;
|
|
374
|
-
|
|
375
|
-
if (!DRY_RUN) {
|
|
376
|
-
writeFileSync(path, JSON.stringify(record, null, 2) + '\n');
|
|
377
|
-
if (existsSync(srcPath)) {
|
|
378
|
-
renameSync(srcPath, join(REJECTED_DIR, imgFile));
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
rejected++;
|
|
382
|
-
} else {
|
|
383
|
-
// Approved — detect category for score profile
|
|
384
|
-
const category = detectCategory(id);
|
|
385
|
-
const profile = category ? CATEGORY_SCORES[category] : CATEGORY_SCORES.prop;
|
|
386
|
-
|
|
387
|
-
record.judgment = {
|
|
388
|
-
status: 'approved',
|
|
389
|
-
reviewer: 'bulk_curate_v2',
|
|
390
|
-
reviewed_at: new Date().toISOString(),
|
|
391
|
-
explanation: profile.explanation,
|
|
392
|
-
criteria_scores: { ...profile.scores },
|
|
393
|
-
failure_modes: [],
|
|
394
|
-
improvement_notes: null,
|
|
395
|
-
confidence: 0.75,
|
|
396
|
-
};
|
|
397
|
-
record.asset_path = `outputs/approved/${imgFile}`;
|
|
398
|
-
|
|
399
|
-
if (!DRY_RUN) {
|
|
400
|
-
writeFileSync(path, JSON.stringify(record, null, 2) + '\n');
|
|
401
|
-
if (existsSync(srcPath)) {
|
|
402
|
-
renameSync(srcPath, join(APPROVED_DIR, imgFile));
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
approved++;
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
console.log(`\n═══ Bulk Curation ${DRY_RUN ? '(DRY RUN) ' : ''}Summary ═══`);
|
|
410
|
-
console.log(`Files scanned: ${files.length}`);
|
|
411
|
-
console.log(`Approved: ${approved}`);
|
|
412
|
-
console.log(`Rejected: ${rejected}`);
|
|
413
|
-
console.log(`Skipped (already curated): ${skipped}`);
|