hexagone-web-feature-extractor
Explore any Hexagone Web space via Playwright headless browser, capture screenshots, and produce a PO-oriented Markdown document.
What this skill does
# Hexagone Web Feature Extractor
Explore a Hexagone Web functional space, capture screenshots of every page/tab, and produce a Markdown document (.md) oriented for Product Owners with functional descriptions and embedded screenshots.
## Prerequisites
- **Node.js** installed
- **Playwright** npm package (`npm install playwright`) — installs headless Chromium automatically
- Network access to the Hexagone Web server (default: `https://ws004202.dedalus.lan:8065/hexagone-01/vue/login`)
## Configuration
Default values calibrated for the standard Hexagone Web layout at 1920x1080. Adjust if the layout differs.
| Parameter | Default | Description |
|-----------|---------|-------------|
| Viewport | `1920x1080` | Browser viewport size |
| Sidebar click X coordinate | `38` | Horizontal pixel position for sidebar icon clicks (collapsed mode) |
| Sidebar max left boundary | `280` | Max `rect.left` value to identify sidebar links (expanded mode) |
| Header height offset | `55` | Min `rect.top` value to exclude header elements |
| Login wait timeout | `30s` | Max time to poll for successful login |
| Page load wait timeout | `10s` | Max time to poll for page load after navigation |
| Screenshots directory | `./screenshots` | Where screenshots are saved (relative to working directory) |
## Workflow Overview
```
1. SETUP → Install Playwright, launch headless Chromium
2. CONNECTION → Log in to Hexagone Web
3. NAVIGATION → Navigate to the target space
4. DISCOVERY → Expand sidebar, list all menu pages
5. EXPLORATION → Visit each page, capture screenshots + metadata
6. GENERATION → Produce the Markdown document with embedded screenshots
```
**Key advantage over Chrome extension approach**: Screenshots save directly to disk via `page.screenshot()` — no bridge server or transfer step needed.
---
## Step 1: Setup
### 1.1 Install Playwright
```bash
npm install playwright
npx playwright install chromium
```
### 1.2 Launch Browser
```javascript
const { chromium } = require('playwright');
const browser = await chromium.launch({
headless: true,
args: ['--ignore-certificate-errors', '--no-sandbox']
});
const context = await browser.newContext({
viewport: { width: 1920, height: 1080 },
ignoreHTTPSErrors: true // Handles self-signed certs automatically
});
const page = await context.newPage();
```
**Why headless Chromium?** Eliminates the need for manual SSL certificate acceptance, Chrome extension setup, and screenshot bridge transfers. The `ignoreHTTPSErrors: true` option handles self-signed certificates programmatically.
---
## Step 2: Connection to Hexagone Web
### 2.1 Navigate to Login Page
```javascript
await page.goto(LOGIN_URL, { waitUntil: 'domcontentloaded', timeout: 30000 });
await sleep(3000); // Wait for Vue.js to mount
```
### 2.2 Fill the Login Form
The Hexagone Web login form has 3 fields: Username, Password, Manager code. Default credentials: username `apvhn` with a random password, unless the user provides others.
Use `page.evaluate()` with the native setter pattern — **required for Vue.js** which does not detect value changes injected directly:
```javascript
await page.evaluate(({ username, password }) => {
const nativeSetter = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype, 'value'
).set;
const userInput = document.querySelector('input[type="text"]');
if (userInput) {
nativeSetter.call(userInput, username);
userInput.dispatchEvent(new Event('input', { bubbles: true }));
}
const pwdInput = document.querySelector('input[type="password"]');
if (pwdInput) {
nativeSetter.call(pwdInput, password);
pwdInput.dispatchEvent(new Event('input', { bubbles: true }));
}
const loginBtn = Array.from(document.querySelectorAll('button'))
.find(b => /connect/i.test(b.textContent));
if (loginBtn) loginBtn.click();
}, { username: USERNAME, password: PASSWORD });
```
### 2.3 Verify Connection
**Poll every 2s for up to 30s** until the URL no longer contains `/login`:
```javascript
for (let i = 0; i < 15; i++) {
await sleep(2000);
if (!page.url().includes('/login')) break;
}
```
**If login fails**: Take a debug screenshot with `page.screenshot()` and report the failure.
---
## Step 3: Navigation to the Target Space
### 3.1 Open the Space Selector
**CRITICAL**: Use `page.mouse.click()` — NOT `el.click()` via `page.evaluate()`.
Vue.js event handlers require native mouse events (mousedown + mouseup + click). JavaScript's `el.click()` only dispatches the `click` event and **will not trigger the space dropdown**. This was the #1 bug found during development.
The space selector is the `div` with class `bg:orange-dark` in the orange breadcrumb bar. It contains an icon `<i class="hexa-icons">changer_espaces</i>` followed by a `<span>` with the current space name.
```javascript
// Find the space selector coordinates
const selectorRect = await page.evaluate(() => {
for (const el of document.querySelectorAll('div, span')) {
const cls = typeof el.className === 'string' ? el.className : '';
if (cls.includes('bg:orange-dark') && !cls.includes('uppercase') && !cls.includes('hover:')) {
const rect = el.getBoundingClientRect();
if (rect.top > 30 && rect.top < 70 && rect.height > 15) {
return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
}
}
}
return null;
});
// Click with REAL mouse events (mandatory for Vue.js)
await page.mouse.click(selectorRect.x, selectorRect.y);
await sleep(3000);
```
### 3.2 Select the Space
The dropdown renders inside the sidebar area as a list of `<div>` elements with class `px:1 py:3/4 hover:bg:orange-dark cursor:pointer`. Spaces are listed alphabetically.
```javascript
// Find the target space element
const target = await page.evaluate((spaceName) => {
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT);
while (walker.nextNode()) {
const el = walker.currentNode;
if (el.textContent.trim() === spaceName) {
const rect = el.getBoundingClientRect();
if (rect.width > 0 && rect.height > 0 && rect.top > 30) {
return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
}
}
}
return null;
}, TARGET_SPACE);
// Click with mouse (not el.click())
await page.mouse.click(target.x, target.y);
```
### 3.3 Wait for Loading
Hexagone Web redirects via an intermediate "Connexion... Redirection..." page. **Poll every 2s for up to 24s** until the URL no longer contains `patient-portal` (the default landing space):
```javascript
for (let i = 0; i < 12; i++) {
await sleep(2000);
if (!page.url().includes('patient-portal')) break;
}
await sleep(3000); // Extra wait for Vue.js rendering
```
---
## Step 4: Page Discovery
### 4.1 Expand the Sidebar
The sidebar is collapsed by default (icons only, width ~65px). Click the hamburger menu to expand it and reveal text labels:
```javascript
await page.mouse.click(34, 50); // Hamburger icon position
await sleep(2000);
```
### 4.2 Identify Sidebar Menu Entries
**Primary method**: Look for elements with `cursor:pointer` class in the left 280px. Strip icon text from `<i class="hexa-icons">` children:
```javascript
const menuItems = await page.evaluate((excludeLabels) => {
const items = [];
const seen = new Set();
const allEls = document.querySelectorAll('[class*="cursor:pointer"], a');
for (const el of allEls) {
const rect = el.getBoundingClientRect();
if (rect.left < 280 && rect.top > 55 && rect.height > 15 && rect.height < 60) {
let text = el.textContent.trim();
// Strip icon prefix text
const icon = el.querySelector('i');
if (icon) text = text.replace(icon.textContent.trim(), '').trim();
if (!text || text.length <= 1 || text.length >= 60 || seen.has(text)) continue;
if (excludeLabels.includes(text)) continue;
// Skip section headers (all-caps short text like "ACHATS")
if (/^[A-Z ]+$/.test(text) &Related in Writing & Docs
jax-development
IncludedUse this skill when the user is writing, debugging, profiling, refactoring, reviewing, benchmarking, parallelising, exporting, or explaining JAX code, or when they mention JAX, jax.numpy, jit, grad, value_and_grad, vmap, scan, lax, random keys, pytrees, jax.Array, sharding, Mesh, PartitionSpec, NamedSharding, pmap, shard_map, Pallas, XLA, StableHLO, checkify, profiler, or the JAX repo. It helps turn NumPy or PyTorch-style code into pure functional JAX, fix tracer/control-flow/shape/PRNG bugs, remove recompiles and host-device syncs, choose transforms and sharding strategies, inspect jaxpr/lowering/IR, and benchmark compiled code correctly.
nature-article-writer
IncludedDrafts, rewrites, diagnostically critiques, and style-calibrates primary research manuscripts for Nature and Nature Portfolio journals. Use when the user wants a Nature-style title, summary paragraph or abstract, introduction, results, discussion, methods, figure legends, presubmission enquiry, cover letter, reviewer response, or when a scientific draft sounds generic, jargon-heavy, structurally weak, or AI-ish and needs precise, broad-reader-friendly prose without inventing data, analyses, or references. Best for primary research articles and letters rather than reviews or press releases unless explicitly adapting one.
deckrd
IncludedDocument-driven framework that derives requirements, specifications, implementation plans, and executable tasks from goals through structured AI dialogue. Use when user says "write requirements", "create spec", "plan implementation", "derive tasks", "structure this feature", "break down into tasks", or "document this module". Also use for reverse engineering existing code into docs (/deckrd rev). Do NOT use for direct code writing — use /deckrd-coder after tasks are generated. Do NOT use when the user only wants to run or fix existing code without planning.
clinical-decision-support
IncludedGenerate professional clinical decision support (CDS) documents for pharmaceutical and clinical research settings, including patient cohort analyses (biomarker-stratified with outcomes) and treatment recommendation reports (evidence-based guidelines with decision algorithms). Supports GRADE evidence grading, statistical analysis (hazard ratios, survival curves, waterfall plots), biomarker integration, and regulatory compliance. Outputs publication-ready LaTeX/PDF format optimized for drug development, clinical research, and evidence synthesis.
handling-sf-data
IncludedSalesforce data operations with 130-point scoring. Use this skill to create, update, delete, bulk import/export, generate test data, and clean up org records using sf CLI and anonymous Apex. TRIGGER when: user creates test data, performs bulk import/export, uses sf data CLI commands, needs data factory patterns for Apex tests, or needs to seed/clean records in a Salesforce org. DO NOT TRIGGER when: SOQL query writing only (use querying-soql), Apex test execution (use running-apex-tests), or metadata deployment (use deploying-metadata).
accelint-ac-to-playwright
IncludedConvert and validate acceptance criteria for Playwright test automation. Use when user asks to (1) review/evaluate/check if AC are ready for automation, (2) assess if AC can be converted as-is, (3) validate AC quality for Playwright, (4) turn AC into tests, (5) generate tests from acceptance criteria, (6) convert .md bullets or .feature Gherkin files to Playwright specs, (7) create test automation from requirements. Handles both bullet-style markdown and Gherkin syntax with JSON test plan generation and validation.