Files
CapaKraken/samples/generate_skillmatrix.mjs
T

415 lines
19 KiB
JavaScript

/**
* Generates skill matrix Excel files for all CapaKraken 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/capakraken/node_modules/.pnpm/xlsx@0.18.5/node_modules/xlsx/xlsx.js");
const OUT_DIR = "/home/hartmut/Documents/Copilot/capakraken/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}`);