Skip to main content

unity-asset-assigner

Automate Unity Asset Store seat/resource assignment for organizations. Use when the user asks to assign, allocate, or distribute Unity Asset Store resources/seats to team members in a Unity organization. Triggers on: 'assign unity assets', 'allocate unity seats', 'distribute unity resources', 'unity asset management', 'unity organization assets', '分配Unity资源', '分配席位', or any request involving bulk assignment of Unity Asset Store purchases to organization members. Also triggers when the user says something like '帮我把我的unity账户下 [org] 组织中的资源分配给 [person]' or 'assign all assets to someone in my Unity org'. This skill requires the camoufox-cli skill as a dependency for anti-detect browser automation.

Source facts

Repository
ziyu/useful-skills
Last source activity
March 14, 2026 at 04:02
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
unity-asset-assigner
description
Automate Unity Asset Store seat/resource assignment for organizations. Use when the user asks to assign, allocate, or distribute Unity Asset Store resources/seats to team members in a Unity organization. Triggers on: 'assign unity assets', 'allocate unity seats', 'distribute unity resources', 'unity asset management', 'unity organization assets', '分配Unity资源', '分配席位', or any request involving bulk assignment of Unity Asset Store purchases to organization members. Also triggers when the user says something like '帮我把我的unity账户下 [org] 组织中的资源分配给 [person]' or 'assign all assets to someone in my Unity org'. This skill requires the camoufox-cli skill as a dependency for anti-detect browser automation.
# Unity Asset Store Bulk Seat Assigner Automates assigning Unity Asset Store resources to organization members via the Unity ID asset management page. This skill handles the entire flow: login, navigation, identifying unassigned assets, and performing the assignment clicks — across all pages and asset types (seat-based and unlimited). ## Prerequisites - `camoufox-cli` installed and working (`npm install -g camoufox-cli`) - Camoufox browser engine downloaded (`camoufox-cli install`) - The camoufox-cli skill should also be loaded for reference on browser commands ## Quick Start When the user says something like "帮我把我的unity账户下 [org] 组织中的资源分配给 [person]", extract: 1. **Organization slug** — the URL segment for the org (e.g., `thezygame`) 2. **Target person** — the name or email of the person to assign to Then follow the workflow below. ## Step 1: Start Browser & Login Use headed mode so the user can manually log in (Unity has strong bot detection on login): ```bash camoufox-cli --session unity --headed --timeout 3600 open "https://id.unity.com/zh/organizations/{org_slug}/manage_assets/seat_managements" ``` If you have saved cookies from a previous session, import them first: ```bash camoufox-cli --session unity --headed --timeout 3600 open "https://id.unity.com" camoufox-cli --session unity cookies import /tmp/unity-cookies.json camoufox-cli --session unity open "https://id.unity.com/zh/organizations/{org_slug}/manage_assets/seat_managements" ``` Check if login succeeded by taking a snapshot — if you see the asset table with links like "Planet Forge", "GPU Instancer Pro", etc., you're in. If redirected to a login/conversation page, tell the user to log in manually in the browser window, then wait for them to confirm. After successful login, always save cookies: ```bash camoufox-cli --session unity cookies export /tmp/unity-cookies.json ``` ## Step 2: Identify the Target User's Checkbox ID The assignment panel uses checkbox IDs that correspond to user IDs in the Unity organization. You need to discover the target user's checkbox ID. Open any asset's assignment panel to find it: ```bash camoufox-cli --session unity eval " var rows = document.querySelectorAll('table tbody tr'); var row = rows[0]; row.scrollIntoView({block: 'center'}); row.dispatchEvent(new MouseEvent('mouseenter', {bubbles: true})); row.dispatchEvent(new MouseEvent('mouseover', {bubbles: true})); row.querySelector('a.ico-add-user').click(); 'opened panel' " ``` Then wait ~1s and find all checkboxes in the panel: ```bash camoufox-cli --session unity eval " var panel = document.querySelector('.alert.txt-l'); var members = panel.querySelectorAll('.member-assign-selection'); var info = []; for (var i = 0; i < members.length; i++) { var m = members[i]; var input = m.querySelector('input[type=checkbox]'); info.push({ name: m.textContent.trim().substring(0, 60), checkboxId: input ? input.id : null }); } JSON.stringify(info, null, 2); " ``` This returns something like: ```json [ {"name": "ZL ziyu li xxxxxx@gmail.com", "checkboxId": "3359866"}, {"name": "YY yy y yyyyyyyy@gmail.com", "checkboxId": "322121967213"} ] ``` Match the target person's name/email to get their checkbox ID. Store it — you'll use it for every assignment. ## Step 3: Set Page Size to 100 Minimize pagination by setting the page size to 100: ```bash camoufox-cli --session unity eval " var sel = document.querySelectorAll('select')[0]; sel.value = '100'; sel.dispatchEvent(new Event('change', {bubbles: true})); 'changed to 100' " ``` Wait 3 seconds for the page to reload, then verify: ```bash camoufox-cli --session unity eval " document.querySelectorAll('table tbody tr').length; " ``` ## Step 4: Find Unassigned Assets Scan the table to find assets that need assignment: ```bash camoufox-cli --session unity eval " var rows = document.querySelectorAll('table tbody tr'); var unassigned = []; for (var i = 0; i < rows.length; i++) { var cells = rows[i].querySelectorAll('td'); if (cells.length >= 5) { var assigned = cells[4] ? cells[4].textContent.trim() : ''; if (assigned.indexOf('{target_username}') < 0) { unassigned.push(i); } } } JSON.stringify({total: rows.length, unassigned: unassigned.length, indices: unassigned}); " ``` Replace `{target_username}` with the target person's username (e.g., `jadeblade`). This catches both seat-based (0/1) and unlimited (无限制) assets. ## Step 5: The Assignment Workflow (Core Loop) This is the critical part. Each assignment follows this exact sequence: ### Why this specific sequence matters The Unity asset management page is a Vue.js app with custom-styled checkboxes. Key discoveries: - The "管理席位" button only appears on hover — it's not in the accessibility tree - Checkboxes are hidden `<input>` elements styled with CSS — the actual `<input>` has 0 dimensions - You must click the `<label>`, then click the `<input>` (to trigger Vue reactivity), then dispatch a `change` event - The "分配席位" button starts with a `disabled` class — it only becomes enabled after the checkbox change event propagates through Vue - There are TWO assignment panels in the DOM — one visible (rendered by Vue inside the table) and one hidden in a `.alert` div. Always target `.alert.txt-l` which is the visible one - After each assignment, the previous panel may still be open and interfere with the next one — always close it first ### Single Assignment Function For each unassigned row index, execute these three steps with sleeps between them: **Step A: Close any open panel, then open the target row's panel** ```bash camoufox-cli --session unity eval " var panel = document.querySelector('.alert.txt-l'); if (panel && panel.getBoundingClientRect().height > 0) { var closeBtn = panel.querySelector('.close, .ico-close, [class*=close]'); if (closeBtn) closeBtn.click(); } 'closed' " ``` Wait 0.5s, then: ```bash camoufox-cli --session unity eval " var rows = document.querySelectorAll('table tbody tr'); var row = rows[{ROW_INDEX}]; row.scrollIntoView({block: 'center'}); row.dispatchEvent(new MouseEvent('mouseenter', {bubbles: true})); row.dispatchEvent(new MouseEvent('mouseover', {bubbles: true})); row.querySelector('a.ico-add-user').click(); 'opened' " ``` **Step B: Check the target user's checkbox and trigger Vue reactivity** Wait 1s after opening the panel, then: ```bash camoufox-cli --session unity eval " var cb = document.getElementById('{CHECKBOX_ID}'); var label = document.querySelector('label[for=\"{CHECKBOX_ID}\"]'); label.click(); cb.click(); if (!cb.checked) { cb.checked = true; } cb.dispatchEvent(new Event('change', {bubbles: true})); setTimeout(function() { var assignBtn = document.querySelector('.alert.txt-l button.btn:not(.bg-re):not(.disabled)'); if (assignBtn) { assignBtn.click(); } }, 500); 'assigned' " ``` **Step C: Wait for the assignment to complete** Wait 2-3 seconds before proceeding to the next asset. ### Batch Processing with Shell Loop For efficiency, process multiple rows in a shell loop: ```bash for idx in {SPACE_SEPARATED_INDICES}; do camoufox-cli --session unity eval " var panel = document.querySelector('.alert.txt-l'); if (panel && panel.getBoundingClientRect().height > 0) { var closeBtn = panel.querySelector('.close, .ico-close, [class*=close]'); if (closeBtn) closeBtn.click(); } 'c' " 2>&1 > /dev/null sleep 0.5 camoufox-cli --session unity eval " var rows = document.querySelectorAll('table tbody tr'); var row = rows[\$idx]; row.scrollIntoView({block: 'center'}); row.dispatchEvent(new MouseEvent('mouseenter', {bubbles: true})); row.dispatchEvent(new MouseEvent('mouseover', {bubbles: true})); row.querySelector('a.ico-add-user').click(); 'o' " 2>&1 > /dev/null sleep 1 camoufox-cli --session unity eval " var cb = document.getElementById('{CHECKBOX_ID}'); var label = document.querySelector('label[for=\"{CHECKBOX_ID}\"]'); label.click(); cb.click(); if (!cb.checked) { cb.checked = true; } cb.dispatchEvent(new Event('change', {bubbles: true})); setTimeout(function() { var assignBtn = document.querySelector('.alert.txt-l button.btn:not(.bg-re):not(.disabled)'); if (assignBtn) { assignBtn.click(); } }, 500); 'a' " 2>&1 > /dev/null sleep 2 echo "done $idx" done ``` ## Step 6: Verify and Retry Failures After each batch, roughly 50% of assignments may silently fail due to the panel interference pattern. This is expected behavior — always verify and retry. ### Verify ```bash camoufox-cli --session unity eval " var rows = document.querySelectorAll('table tbody tr'); var remaining = []; for (var i = 0; i < rows.length; i++) { var cells = rows[i].querySelectorAll('td'); if (cells.length >= 5) { var assigned = cells[4] ? cells[4].textContent.trim() : ''; if (assigned.indexOf('{target_username}') < 0) { remaining.push(i); } } } JSON.stringify({count: remaining.length, indices: remaining}); " ``` ### Retry If there are remaining unassigned assets, run the batch loop again with the failed indices. Use slightly longer sleep (3s instead of 2s) for retries. Usually one retry pass is enough to catch all failures. ## Step 7: Handle Pagination After clearing all unassigned assets on the current page, check for more pages: ```bash camoufox-cli --session unity eval " var nextBtn = document.querySelector('a.next'); var nextDisplay = nextBtn ? window.getComputedStyle(nextBtn).display : 'none'; JSON.stringify({hasNextPage: nextDisplay !== 'none'}); " ``` If there's a next page: ```bash camoufox-cli --session unity eval " document.querySelector('a.next').click(); 'next page' " ``` Wait 3 seconds, then repeat Steps 4-6 for the new page. Continue until `hasNextPage` is false. To go back to page 1: ```bash camoufox-cli --session unity eval " document.querySelector('a.first').click(); 'page 1' " ``` ## Step 8: Final Verification After processing all pages, go back to page 1 and scan through every page one more time to confirm zero unassigned assets remain. ## Step 9: Save Cookies & Cleanup ```bash camoufox-cli --session unity cookies export /tmp/unity-cookies.json ``` Don't close the browser session unless the user asks — they may want to verify visually. ## Known Issues & Workarounds ### ~50% Silent Failure Rate Per Batch The assignment panel from the previous row sometimes interferes with the next row's panel. The "close panel" step mitigates this but doesn't eliminate it entirely. Always verify after each batch and retry failures. Usually takes 1-2 retry passes to get 100%. ### Browser Daemon Crashes The camoufox daemon can disconnect after certain operations (page navigation, long waits, reload). If you get "Browser not launched" errors: 1. Restart: `camoufox-cli --session unity --headed --timeout 3600 open "https://id.unity.com"` 2. Import cookies: `camoufox-cli --session unity cookies import /tmp/unity-cookies.json` 3. Navigate back to the asset page ### Snapshot Doesn't Show Assignment Panel Elements The assignment panel elements (checkboxes, buttons) don't appear in `camoufox-cli snapshot` output because they're not in the accessibility tree. Always use `eval` with JavaScript to interact with these elements. ### Row Indices Shift After Assignments When seat-based assets change from 0/1 to 1/1, the page may re-sort or the total row count may change. Always re-scan for unassigned indices after each batch rather than relying on previously computed indices. ## Page Structure Reference The Unity asset management table has these columns: | Column | Index | Content | |--------|-------|---------| | 资源名称 | 0 | Asset name with link | | 许可证 | 1 | License type | | 席位 | 2 | "0/1", "1/1", or "无限制" | | 购买日期 | 3 | Purchase date | | 分配/共享对象 | 4 | Assigned users or "管理席位" | | 标签 | 5 | Tags | Asset types: - **席位 (Seat-based)**: Shows "0/1" (unassigned) or "1/1" (assigned). Limited seats. - **无限制 (Unlimited/Entity-based)**: Shows "无限制". Can be assigned to multiple users. Both types use the same assignment workflow.
View on GitHub