415 lines
19 KiB
JavaScript
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}`);
|