poooi/poi/game-webview
- community
Checking that the SKILL.md file is still in the repository.
The KanColle game <webview> — contextIsolation + disablewebsecurity, the preload world split, the poi-cache:// asset-hack scheme, and the window.open popup crash. Use when editing views/kan-game-wrapper.tsx, assets/js/webview-preload.js, assets/js/resource-hack.js, assets/js/kcs-resource-path.js, lib/kcs-resource.ts, lib/webcontent-utils.ts, or when debugging game asset loading, screenshots, renderer crashes, or webview security settings.
Install
npx vskill@latest install poooi/poi/game-webviewSKILL.md
Game Webview
Security posture
The game <webview> (views/kan-game-wrapper.tsx) runs with contextIsolation: true and disablewebsecurity. The preload (assets/js/webview-preload.js) runs in the isolated world — keeping Node and @electron/remote — and pushes page-facing hacks into the page's main world via contextBridge.executeInMainWorld, communicating through the exposed poiPreloadBridge.
Why `disablewebsecurity` stays: enabling standard web security in the page's main world breaks (a) the cross-origin game-iframe traversal used by the canvas screenshot (window.capture in capture-page.js) and (b) historically file:// asset loads. The canvas capture is deliberately kept (better raw/resize-correct screenshots), so disablewebsecurity must remain. contextIsolation still isolates the preload's Node from the untrusted page — that is the security win.
The main poi window and plugin windows remain contextIsolation: false (plugins run Node in-page) — out of scope for this skill.
Asset hack — everything serves through poi-cache://
lib/kcs-resource.ts registers a privileged poi-cache:// scheme plus a handler that net.fetches the local file, sets ACAO: *, and sets an explicit Content-Type by extension. Two trigger paths:
Scripts — two-tier policy
.hack.*script overrides are served proactively by the main-processwebRequest
(override-only, so a mod always applies).
- Plain cached scripts are served only on load failure: a page-side capture-phase
error listener in resource-hack.js re-injects a /kcs* script from cache when its network load fails.
- Proactive plain-cache serving is forbidden: stale version-pinned scripts
(main.js?version=...) plus gadget RPC under /gadget_html5/ break login with Unexpected identifier 'error'. This was tried both ways — do not re-attempt.
- The separate login
onErrorpath (runtimekcsLoginfailure) still re-injects and re-runs
the gadget handlers, which webRequest cannot do — so the page-side fallback stays regardless.
Images and login scripts — page-side
resource-hack.js: an isolated-world resolver maps to poi-cache://resource<pathname>, applied by the main-world new Image() hook and login-script reinjection.
Ship art is drawn onto the game's WebGL canvas, and a cross-origin image taints the texture (texImage2D SecurityError). The fix is a CORS-clean load: the new Image() hook sets crossOrigin = 'anonymous' on hacked images, paired with the handler's ACAO: *. Only hacked images get crossOrigin, so same-origin network images are untouched. Images are deliberately not in the webRequest path (page-side crossOrigin avoids both the WebGL taint and a 400).
stylesheet / media / font / script — main-process webRequest.onBeforeRequest
HACKABLE_RESOURCE_TYPES = { stylesheet, media, font, script }. stylesheet/media/font resolve .hack.* first, then the plain cached origin. script is in OVERRIDE_ONLY_RESOURCE_TYPES, so findHackFilePathAsync(..., overrideOnly = true) serves only .hack.*. xhr and documents are excluded because login evaluates XHR bodies.
Implementation notes
- Content-Type comes from the
mimepackage (v4, ESM-only) via a cached native dynamic
import('mime') plus import type { Mime }. Babel keeps import() for poi files; a static import would transpile to a broken require of an ESM-only package.
- The webview uses
session.defaultSession(no partition) — confirmed byresource-notifier.ts
also hooking defaultSession.
- Shared path logic is plain JS in
assets/js/kcs-resource-path.js, required from both the main
process and the renderer preload, because main only babel-registers .es / .ts / .tsx.
- Broadcaster events (
network.on.responseetc.) are consumed in
views/env-parts/data-resolver.ts, filtered to /kcsapi plus the /kcs2/js/main.js game-start marker — so the bridge's input validation allows the /kcs prefix.
The window.open popup crash (diagnosed 2026-08-07)
Opening the DMM point-charge page (point.dmm.com/choice/pay -> /choice/point) from the game killed the renderer: reason: "crashed", exit code -2147483645 (0x80000003 STATUS_BREAKPOINT), twice per attempt, with no CHECK/FATAL line in either the Chromium log or stderr.
Root cause: disablewebsecurity. A window.open popup keeps an opener relationship with the game page and therefore shares its renderer process; loading an ordinary secure page into that web-security-disabled process crashes it, taking the game down too.
Fix: wc.setWindowOpenHandler on the guest webContents in lib/webcontent-utils.ts — deny http(s) popups and re-open them in a detached BrowserWindow (webSecurity: true, sandbox: true, no node), which drops the opener link. about:blank popups still take the normal allow path, since the opener scripts them.
Ruled out — do not re-test: --disable-site-isolation-trials (app.ts), devtools extensions (poi.devtool.enable), the proxy, Sentry, plugins, @electron/remote, and inherited webPreferences (Electron's makeWebPreferences does _not_ inherit preload or disablewebsecurity into child windows). A top-level window loading the same URL never crashes — the opener relationship is required to reproduce. The original symptom was a misleading @electron/remote / Sentry error about a disposed WebFrameMain, which is downstream of the crash, not its cause.
Deferred: WebContentsView migration
Replacing <webview> with WebContentsView has been scoped but deferred — it is blocked on an Electron per-view click-through API. Do not start it without checking with the user.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/game-webview/SKILL.md
Popularity
- Repository stars
- 1,800
- Repository forks
- 362
- 7-day trend score
- 0
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/poooi/poi/game-webview)