/** * Generates skill matrix Excel files for all Planarchy resources. * Format matches skillmatrix_formular_example.xlsx exactly. */ import { createRequire } from "module"; import { writeFileSync, mkdirSync } from "fs"; const require = createRequire(import.meta.url); const XLSX = require("/home/hartmut/Documents/Copilot/planarchy/node_modules/.pnpm/xlsx@0.18.5/node_modules/xlsx/xlsx.js"); const OUT_DIR = "/home/hartmut/Documents/Copilot/planarchy/samples/skillmatrix_dummydata"; mkdirSync(OUT_DIR, { recursive: true }); // ─── Skill Definitions ───────────────────────────────────────────────────── const SOFTWARE_SKILLS = [ // 3D Editing { category: "3D Editing", item: "3ds max" }, { category: "3D Editing", item: "Maya" }, { category: "3D Editing", item: "Blender" }, { category: "3D Editing", item: "Modo" }, { category: "3D Editing", item: "Cinema4D" }, { category: "3D Editing", item: "Houdini" }, { category: "3D Editing", item: "ZBrush" }, // 2D Creation { category: "2D Creation", item: "Photoshop" }, { category: "2D Creation", item: "Illustrator" }, { category: "2D Creation", item: "After Effects" }, { category: "2D Creation", item: "Substance Painter" }, { category: "2D Creation", item: "Substance Designer" }, { category: "2D Creation", item: "Procreate" }, // Automotive Pipeline { category: "Automotive Pipeline", item: "VPB" }, { category: "Automotive Pipeline", item: "Data Pipeline" }, { category: "Automotive Pipeline", item: "EFC" }, { category: "Automotive Pipeline", item: "VMDS" }, { category: "Automotive Pipeline", item: "Batch Export Tools" }, { category: "Automotive Pipeline", item: "JT Format Tools" }, // Game Engines { category: "Game Engines", item: "Unreal Engine" }, { category: "Game Engines", item: "Unity" }, { category: "Game Engines", item: "CryEngine" }, // Development { category: "Development", item: "Python" }, { category: "Development", item: "JavaScript" }, { category: "Development", item: "TypeScript" }, { category: "Development", item: "C++" }, { category: "Development", item: "MEL / MaxScript" }, { category: "Development", item: "Node.js" }, { category: "Development", item: "Git" }, // Rendering { category: "Rendering", item: "V-Ray" }, { category: "Rendering", item: "Arnold" }, { category: "Rendering", item: "Corona" }, { category: "Rendering", item: "Octane" }, { category: "Rendering", item: "Redshift" }, { category: "Rendering", item: "Cycles" }, { category: "Rendering", item: "Marmoset Toolbag" }, // Collaboration { category: "Collaboration & PM", item: "Jira" }, { category: "Collaboration & PM", item: "Confluence" }, { category: "Collaboration & PM", item: "MS Project" }, { category: "Collaboration & PM", item: "Excel" }, { category: "Collaboration & PM", item: "PowerPoint" }, { category: "Collaboration & PM", item: "Shotgun / ShotGrid" }, ]; const TECHNICAL_SKILLS = [ // Industry experience { category: "Industry Experience", item: "Automotive" }, { category: "Industry Experience", item: "Arch viz / Real estate" }, { category: "Industry Experience", item: "Environments" }, { category: "Industry Experience", item: "Product viz" }, { category: "Industry Experience", item: "Character creation" }, { category: "Industry Experience", item: "VFX" }, { category: "Industry Experience", item: "Games" }, // Output formats { category: "Output Format", item: "Offline rendering" }, { category: "Output Format", item: "Real-time / Configurator" }, { category: "Output Format", item: "Interactive (AR/VR)" }, { category: "Output Format", item: "360° / Panorama" }, { category: "Output Format", item: "Motion picture" }, // File formats { category: "File Formats", item: "FBX" }, { category: "File Formats", item: "OBJ / MTL" }, { category: "File Formats", item: "USD / USDZ" }, { category: "File Formats", item: "Alembic" }, { category: "File Formats", item: "glTF / glb" }, { category: "File Formats", item: "JT" }, { category: "File Formats", item: "3MF" }, // Asset types { category: "Asset Types", item: "Hard surface / Vehicles" }, { category: "Asset Types", item: "Organic / Characters" }, { category: "Asset Types", item: "Interior / Props" }, { category: "Asset Types", item: "Exterior / Architecture" }, { category: "Asset Types", item: "Materials & Textures" }, { category: "Asset Types", item: "Lighting & HDRI" }, // Quality & Pipeline { category: "Quality & Pipeline", item: "Asset QA" }, { category: "Quality & Pipeline", item: "Performance optimization" }, { category: "Quality & Pipeline", item: "LOD creation" }, { category: "Quality & Pipeline", item: "Data validation" }, { category: "Quality & Pipeline", item: "Bug tracking" }, { category: "Quality & Pipeline", item: "Review & Feedback" }, ]; // ─── Profile Templates per Chapter ───────────────────────────────────────── /** * Seeded random number generator for reproducible results. */ function seededRandom(seed) { let s = seed; return () => { s = (s * 16807 + 0) % 2147483647; return (s - 1) / 2147483646; }; } function rand(rng, min, max) { return Math.floor(rng() * (max - min + 1)) + min; } function pick(rng, ...choices) { return choices[Math.floor(rng() * choices.length)]; } /** * Returns skill levels for all software+technical skills based on chapter profile. * Each skill gets a property 0-4 (0=no experience) and optionally a main skillset marker. */ function buildSkillProfile(resource, seed) { const rng = seededRandom(seed); const chapter = resource.chapter ?? "Digital Content Production"; // Determine area of expertise and portfolio based on chapter let areaOfExpertise, yearsOfExperience, portfolioUrl; if (chapter === "Project Management") { areaOfExpertise = "Project Manager"; yearsOfExperience = rand(rng, 4, 15); portfolioUrl = ""; } else if (chapter === "Art Direction") { areaOfExpertise = "Art Director"; yearsOfExperience = rand(rng, 5, 18); portfolioUrl = `https://www.artstation.com/${resource.eid.split(".")[0]}`; } else if (chapter === "Product Data Management") { areaOfExpertise = "PDM Specialist"; yearsOfExperience = rand(rng, 3, 12); portfolioUrl = ""; } else if (chapter === "CGI-Dev") { areaOfExpertise = pick(rng, "Unreal Dev", "Frontend Dev", "3D Tech Tester"); yearsOfExperience = rand(rng, 2, 12); portfolioUrl = `https://github.com/${resource.eid.split(".")[0]}`; } else { // Digital Content Production areaOfExpertise = pick(rng, "3D Artist", "3D Lead", "3D Generalist"); yearsOfExperience = rand(rng, 2, 14); portfolioUrl = `https://www.artstation.com/${resource.eid.split(".")[0]}`; } /** * Returns proficiency 0-4 for a given skill based on chapter profile. */ function getSkillLevel(category, item) { const c = chapter; const base = rng(); // Project Management chapter if (c === "Project Management") { if (category === "Collaboration & PM") return rand(rng, 3, 4); if (item === "Photoshop" || item === "Illustrator") return rand(rng, 1, 3); if (item === "3ds max" || item === "Maya") return rand(rng, 0, 1); if (item === "Unreal Engine" || item === "Unity") return rand(rng, 0, 1); if (category === "Automotive Pipeline") return rand(rng, 2, 4); if (category === "Industry Experience") return rand(rng, 1, 3); if (category === "Output Format") return rand(rng, 1, 2); if (category === "Quality & Pipeline") return rand(rng, 2, 4); if (category === "File Formats") return rand(rng, 1, 2); if (category === "Asset Types") return rand(rng, 0, 1); return base > 0.7 ? rand(rng, 1, 2) : 0; } // Art Direction if (c === "Art Direction") { if (item === "Photoshop") return rand(rng, 3, 4); if (item === "Illustrator") return rand(rng, 3, 4); if (item === "After Effects") return rand(rng, 2, 4); if (item === "Cinema4D" || item === "Blender") return rand(rng, 2, 3); if (item === "3ds max" || item === "Maya") return rand(rng, 2, 4); if (item === "ZBrush") return rand(rng, 1, 3); if (item === "Substance Painter") return rand(rng, 2, 3); if (category === "Automotive Pipeline") return rand(rng, 2, 3); if (category === "Industry Experience") return rand(rng, 2, 4); if (item === "Real-time / Configurator") return rand(rng, 2, 3); if (item === "Offline rendering") return rand(rng, 3, 4); if (category === "Asset Types") return rand(rng, 2, 4); if (category === "Rendering") return rand(rng, 2, 4); if (category === "Collaboration & PM") return rand(rng, 1, 3); return base > 0.5 ? rand(rng, 1, 2) : 0; } // Product Data Management if (c === "Product Data Management") { if (category === "Automotive Pipeline") return rand(rng, 3, 4); if (category === "File Formats") return rand(rng, 3, 4); if (item === "Asset QA" || item === "Data validation") return rand(rng, 3, 4); if (item === "Performance optimization" || item === "LOD creation") return rand(rng, 2, 4); if (item === "Excel" || item === "PowerPoint") return rand(rng, 3, 4); if (item === "Jira" || item === "Confluence") return rand(rng, 2, 3); if (item === "FBX" || item === "OBJ / MTL") return rand(rng, 3, 4); if (item === "JT" || item === "3MF") return rand(rng, 3, 4); if (item === "Automotive") return rand(rng, 3, 4); if (item === "Hard surface / Vehicles") return rand(rng, 3, 4); if (category === "3D Editing") return rand(rng, 1, 3); if (category === "Industry Experience") return rand(rng, 2, 3); if (category === "Quality & Pipeline") return rand(rng, 2, 4); return base > 0.6 ? rand(rng, 1, 2) : 0; } // CGI-Dev if (c === "CGI-Dev") { if (item === "Unreal Engine") return rand(rng, 3, 4); if (item === "Unity") return rand(rng, 2, 4); if (item === "Python") return rand(rng, 3, 4); if (item === "JavaScript" || item === "TypeScript") return rand(rng, 3, 4); if (item === "C++") return rand(rng, 2, 4); if (item === "Node.js") return rand(rng, 2, 3); if (item === "Git") return rand(rng, 3, 4); if (item === "MEL / MaxScript") return rand(rng, 2, 3); if (item === "Real-time / Configurator") return rand(rng, 3, 4); if (item === "Interactive (AR/VR)") return rand(rng, 2, 4); if (category === "Automotive Pipeline") return rand(rng, 2, 3); if (item === "Asset QA" || item === "Performance optimization") return rand(rng, 3, 4); if (item === "LOD creation") return rand(rng, 2, 4); if (item === "glTF / glb" || item === "FBX") return rand(rng, 3, 4); if (item === "Automotive" || item === "Games") return rand(rng, 3, 4); if (category === "3D Editing") return rand(rng, 1, 3); if (category === "2D Creation") return rand(rng, 0, 2); if (category === "Rendering") return rand(rng, 1, 2); return base > 0.5 ? rand(rng, 1, 2) : 0; } // Digital Content Production (3D Artists) if (item === "3ds max") return rand(rng, 3, 4); if (item === "Maya") return rand(rng, 2, 4); if (item === "Blender") return rand(rng, 1, 3); if (item === "Cinema4D") return rand(rng, 0, 3); if (item === "Houdini") return rand(rng, 0, 2); if (item === "ZBrush") return rand(rng, 1, 3); if (item === "Photoshop") return rand(rng, 3, 4); if (item === "Substance Painter") return rand(rng, 2, 4); if (item === "Substance Designer") return rand(rng, 1, 3); if (item === "V-Ray") return rand(rng, 2, 4); if (item === "Arnold") return rand(rng, 1, 3); if (item === "Redshift") return rand(rng, 1, 3); if (item === "Corona") return rand(rng, 0, 2); if (category === "Automotive Pipeline") return rand(rng, 2, 4); if (item === "Automotive") return rand(rng, 2, 4); if (item === "Hard surface / Vehicles") return rand(rng, 3, 4); if (item === "Materials & Textures") return rand(rng, 3, 4); if (item === "FBX" || item === "OBJ / MTL") return rand(rng, 3, 4); if (item === "Offline rendering") return rand(rng, 3, 4); if (item === "Real-time / Configurator") return rand(rng, 2, 3); if (category === "Quality & Pipeline") return rand(rng, 2, 3); if (category === "Asset Types") return rand(rng, 2, 4); if (category === "Collaboration & PM") return rand(rng, 1, 3); return base > 0.6 ? rand(rng, 1, 2) : 0; } // Build skill rows const softwareRows = SOFTWARE_SKILLS.map(({ category, item }) => ({ category, item, property: String(getSkillLevel(category, item)), "main skillset": "please select", })); const technicalRows = TECHNICAL_SKILLS.map(({ category, item }) => ({ category, item, property: String(getSkillLevel(category, item)), "main skillset": "", })); // Pick 2 main skills: the top 2 Software Skills with property > 0 const eligibleMain = softwareRows .filter((r) => parseInt(r.property) >= 3) .sort((a, b) => parseInt(b.property) - parseInt(a.property)) .slice(0, 2); eligibleMain.forEach((row, idx) => { row["main skillset"] = String(idx + 1); // "1" for first, "2" for second }); return { areaOfExpertise, yearsOfExperience, portfolioUrl, softwareRows, technicalRows, }; } // ─── Excel Generation ─────────────────────────────────────────────────────── function createWorkbook(resource, profile) { const wb = XLSX.utils.book_new(); // Sheet 1: Introduction (minimal placeholder) const introData = [ { Introduction: "Skill Matrix — auto-generated for testing" }, ]; const wsIntro = XLSX.utils.json_to_sheet(introData); XLSX.utils.book_append_sheet(wb, wsIntro, "Introduction"); // Sheet 2: Employee Information const empData = [ { "__EMPTY": "", item: "full name", property: resource.displayName }, { "__EMPTY": "", item: "area of expertise/main focus", property: profile.areaOfExpertise }, { "__EMPTY": "", item: "years of experience", property: String(profile.yearsOfExperience) + ".0" }, { "__EMPTY": "", item: "Creative Portfolio", property: profile.portfolioUrl || "https://www.example.com/" + resource.eid, }, ]; const wsEmp = XLSX.utils.json_to_sheet(empData); XLSX.utils.book_append_sheet(wb, wsEmp, "Employee Information"); // Sheet 3: Software Skills const wsSoftware = XLSX.utils.json_to_sheet(profile.softwareRows); XLSX.utils.book_append_sheet(wb, wsSoftware, "Software Skills"); // Sheet 4: Technical Skillset const wsTechnical = XLSX.utils.json_to_sheet(profile.technicalRows); XLSX.utils.book_append_sheet(wb, wsTechnical, "Technical Skillset"); // Sheet 5: Setup (minimal) const setupData = [ { "area of expertise": profile.areaOfExpertise, "Career Level": "10", "skill level": "3", "main toolset": "1", "type of work": "Automotive", }, ]; const wsSetup = XLSX.utils.json_to_sheet(setupData); XLSX.utils.book_append_sheet(wb, wsSetup, "Setup"); return wb; } // ─── Main ─────────────────────────────────────────────────────────────────── const resources = [ { eid: "anna.marie", displayName: "Anna Marie", chapter: "Product Data Management" }, { eid: "bruce.banner", displayName: "Bruce Banner", chapter: "Project Management" }, { eid: "carl.lucas", displayName: "Carl Lucas", chapter: "CGI-Dev" }, { eid: "carol.danvers", displayName: "Carol Danvers", chapter: "CGI-Dev" }, { eid: "charles.xavier", displayName: "Charles Xavier", chapter: "Project Management" }, { eid: "clint.barton", displayName: "Clint Barton", chapter: "Product Data Management" }, { eid: "danny.rand", displayName: "Danny Rand", chapter: "CGI-Dev" }, { eid: "drax.drax", displayName: "Drax Drax", chapter: "Art Direction" }, { eid: "erik.lehnsherr", displayName: "Erik Lehnsherr", chapter: "Digital Content Production" }, { eid: "frank.castle", displayName: "Frank Castle", chapter: "CGI-Dev" }, { eid: "gamora.gamora", displayName: "Gamora Gamora", chapter: "Project Management" }, { eid: "groot.groot", displayName: "Groot Groot", chapter: "Art Direction" }, { eid: "hank.mccoy", displayName: "Hank Mccoy", chapter: "Product Data Management" }, { eid: "james.barnes", displayName: "James Barnes", chapter: "Digital Content Production" }, { eid: "jean.grey", displayName: "Jean Grey", chapter: "Digital Content Production" }, { eid: "jessica.drew", displayName: "Jessica Drew", chapter: "Digital Content Production" }, { eid: "jessica.jones", displayName: "Jessica Jones", chapter: "CGI-Dev" }, { eid: "kamala.khan", displayName: "Kamala Khan", chapter: "CGI-Dev" }, { eid: "logan.howlett", displayName: "Logan Howlett", chapter: "Digital Content Production" }, { eid: "matt.murdock", displayName: "Matt Murdock", chapter: "CGI-Dev" }, { eid: "miles.morales", displayName: "Miles Morales", chapter: "Digital Content Production" }, { eid: "natasha.romanoff", displayName: "Natasha Romanoff", chapter: "Project Management" }, { eid: "ororo.munroe", displayName: "Ororo Munroe", chapter: "Project Management" }, { eid: "peter.parker", displayName: "Peter Parker", chapter: "Digital Content Production" }, { eid: "peter.quill", displayName: "Peter Quill", chapter: "Product Data Management" }, { eid: "rocket.rocket", displayName: "Rocket Rocket", chapter: "Art Direction" }, { eid: "sam.wilson", displayName: "Sam Wilson", chapter: "Digital Content Production" }, { eid: "scott.summers", displayName: "Scott Summers", chapter: "Project Management" }, { eid: "stephen.strange", displayName: "Stephen Strange", chapter: "Digital Content Production" }, { eid: "steve.rogers", displayName: "Steve Rogers", chapter: "Project Management" }, { eid: "tchalla.tchalla", displayName: "Tchalla Tchalla", chapter: "Art Direction" }, { eid: "thor.odinson", displayName: "Thor Odinson", chapter: "Digital Content Production" }, { eid: "tony.stark", displayName: "Tony Stark", chapter: "Digital Content Production" }, { eid: "vision.vision", displayName: "Vision Vision", chapter: "Art Direction" }, { eid: "wanda.maximoff", displayName: "Wanda Maximoff", chapter: "Digital Content Production" }, { eid: "wong.wong", displayName: "Wong Wong", chapter: "Digital Content Production" }, ]; let count = 0; for (const resource of resources) { // Use a hash-like seed from the eid string const seed = resource.eid.split("").reduce((acc, c) => acc + c.charCodeAt(0), 0) * 31 + 1; const profile = buildSkillProfile(resource, seed); const wb = createWorkbook(resource, profile); const filename = `${resource.eid}.xlsx`; const filepath = `${OUT_DIR}/${filename}`; XLSX.writeFile(wb, filepath); const mainSkills = profile.softwareRows .filter((r) => r["main skillset"] === "1" || r["main skillset"] === "2") .map((r) => r.item); console.log(`✓ ${filename} — ${profile.areaOfExpertise}, ${profile.yearsOfExperience}y, main: [${mainSkills.join(", ")}]`); count++; } console.log(`\nGenerated ${count} skill matrix files in ${OUT_DIR}`);