Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/launcher/src/components/SkillLabelsSettings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ describe("skill label customization", () => {
it("captures physical keyboard labels without changing other slots", async () => {
const save = vi.fn<(patch: LauncherSettingsPatch) => Promise<void>>(async () => undefined);
const wrapper = mount(SkillLabelsSettings, { props: { bindings: EMPTY_SKILL_KEY_BINDINGS, save } });
expect(wrapper.text()).toContain("Skill 1 · 1 (default)");
expect(wrapper.text()).toContain("Skill 8 · 8 (default)");
await wrapper.get('[aria-label="Set skill 3 label"]').trigger("click");
await wrapper.get('[aria-label="Skill label capture"]').trigger("keydown", { code: "KeyG", key: "g", ctrlKey: true });
await flushPromises();
Expand Down
6 changes: 3 additions & 3 deletions apps/launcher/src/components/SkillLabelsSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ async function capture(input: SkillKeyInput, event: KeyboardEvent | MouseEvent |

<template>
<div class="skill-label-settings">
<p>These labels do not change Guild Wars key bindings. Match the controls you use in the game.</p>
<p>These labels do not change Guild Wars key bindings. Unset slots use 1–8. Set custom labels to match your game controls.</p>
<div v-for="(binding, index) in bindings" :key="index" class="skill-label-row">
<span>Skill {{ index + 1 }} · {{ binding ? skillKeyPresentation(binding).accessibleLabel : 'No label' }}</span>
<span>Skill {{ index + 1 }} · {{ binding ? skillKeyPresentation(binding).accessibleLabel : `${index + 1} (default)` }}</span>
<button class="secondary" :aria-label="`Set skill ${index + 1} label`" @click="start(index)">Set label</button>
<button class="text-link" :disabled="!binding" :aria-label="`Clear skill ${index + 1} label`" @click="clear(index)">Clear</button>
<button class="text-link" :disabled="!binding" :aria-label="`Reset skill ${index + 1} label`" @click="clear(index)">Use default</button>
</div>
<template v-if="slot !== null">
<div ref="target" tabindex="0" class="capture-target" aria-label="Skill label capture"
Expand Down
38 changes: 38 additions & 0 deletions docs/effect-timers.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,41 @@ Automated evidence covers native countdown corrections, clock wrap, identity
changes, notification rejection, snapshot validation, dragging, cancellation,
locking, saved offsets, and launcher controls. A Developer Build still needs
live QA for real drink types, map travel, visual alignment, and input feel.

## Native drawing

Skill shortcuts, skill cooldowns, and effect timers share the detached atlas in
[`native-hud-layer.ts`](../src/renderer/native-hud-layer.ts). Timer changes update
small glyph meshes. Cached digits and all three urgency colors avoid repeated
pixel uploads. Digits share fixed-width cells with centered glyphs so changing
numbers does not shift their alignment. Effect labels retain their resource slots when another effect
expires. Effect numbers sit inside the lower-right artwork with a proportional
inset. The bottom duration bar and icon border remain clear.

[`native-hud-transform.ts`](../src/main/certification/native-hud-transform.ts)
attaches those meshes after each native icon's last visible descendant, in the
final clipped draw category. Each skill icon has one draw and one mesh containing
its keycap triangles followed by its cooldown triangles. Separate native draw
objects must not represent these overlapping parts: collection order alone
does not guarantee their downstream order. The stock icon and veil draw before
the composition. Later native panels and tooltips cover it. The transform
checks exact native functions, the Effects parent hash, and the child identity.
Skill labels attach to the visible bitmap child of each logical skill slot.
The draw captures the native UI projection and ancestor opacity directly; it
does not require the logical container to own a reusable bitmap. Geometry and
timer changes reuse the retained draw. New and recreated meshes receive their
geometry on the first draw, even when the icon bounds have not changed. A timer
does not wait for its next digit change to appear. For a matched icon, the
collector reports
empty intermediate slots on the final descendant so the native cache reaches
the label category.
Other frames keep their original stopping point. Skill Key Labels replaces all
eight keycaps: custom bindings where configured, otherwise 1–8. The exact native
hotkey child is omitted while its replacement is active and restored when the
feature withdraws. Keycaps match the original 17-unit visible artwork within
each 56-unit skill icon. The stock 24-unit tile has seven transparent units above
and left. Their size and corner inset follow the interface scale without
fixed pixel limits. Long chords shrink only when needed to fit the icon.
The game's key bindings and icon artwork stay unchanged.
Native icon destruction, disabling the feature, and graphics reset release the
owned resources. Missing native drawing support produces no browser fallback.
32 changes: 22 additions & 10 deletions docs/skill-cooldowns.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,25 +84,37 @@ joins the two complete eight-slot records.
Text updates are bounded by the formatter's visible output. Above three seconds
the view changes only when the upward-rounded whole second changes. Below three
seconds it changes only when the upward-rounded tenth changes. Ready skills
have no label. The complete overlay hides when either source is unavailable,
have no label. The native labels hide when either source is unavailable,
stale, malformed, loading, or denied by the existing Tools/PvE policy.

## Presentation and remaining acceptance

The HUD and Settings preview share
[`skill-cooldown-view.ts`](../src/renderer/skill-cooldown-view.ts), including
the extracted `Guild Wars Original Display` font, outline, shadow, optical
offset, scale, formatter, and color tokens. The one canonical setting accepts
red, cream, gold, blue, or an exact six-digit custom RGB value.
The native HUD uses a cached glyph atlas in
[`native-hud-layer.ts`](../src/renderer/native-hud-layer.ts), the extracted
`Guild Wars Original Display` font, and the existing formatter and color setting.
Digits use equal-width cells and centered visible glyph bounds. Changing a digit
preserves its cell position even when the original font has different widths or
bearings. Decimal and long labels use smaller scales. The canonical color
setting accepts red, cream, gold, blue, or an exact six-digit custom RGB value.

[`skill-cooldown-visual.ts`](../scripts/skill-cooldown-visual.ts) creates the
required duration/color/size/key-coexistence matrix at 1x, 1.5x, and 2x. It can
place the view over a real native skill crop and writes reference, rendered,
and difference images. This remains a calibration aid, not live acceptance.
The atlas allocates on first use. It stays cached across brief idle periods so a
new cooldown does not need another pixel upload. Repacking for changed artwork
republishes current geometry and withdraws removed labels.

[`skill-cooldown-visual.ts`](../scripts/skill-cooldown-visual.ts) replays the actual
native atlas and ordered quads for its duration/color/size/key-coexistence matrix
at 1x, 1.5x, and 2x. It can place the drawing over a real native skill crop and
writes reference, rendered, and difference images. It verifies artwork and
geometry; native GPU ordering and live acceptance remain separate checks.

Live acceptance requires both closed diagnostics and visual confirmation. The
session must record first observations for skill geometry and cooldowns;
Settings must show both live states as working; and a recharging skill must show
the expected number over the correct native slot. Signed bottom-left frame
coordinates are valid when a slot intersects the viewport, even when one edge
is negative. Synthetic output alone cannot close this item.

The skill labels and shortcut badges attach to the certified SkillBar's native
child icons. Their shared drawing lifetime and resource rules are documented
under [Native drawing](effect-timers.md#native-drawing). There is no positioned
browser HUD drawing path.
11 changes: 10 additions & 1 deletion docs/wasm-host.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,12 +222,21 @@ After that restart, these choices update during the session:
- **Target distance and range** controls the shipped Test readout and its target
observation.
- **Skill Key Labels** controls renderer-owned labels over the certified
skill-slot rectangles. Saved bindings remain when the tool is off. The
skill-slot rectangles. All eight use the same keycap style: custom labels where
set, otherwise 1–8. Original keycaps return when the tool is off. Saved
bindings remain. The
companion publishes geometry, not bindings, and the renderer never turns a
label into game input.
- **Skill Cooldowns** controls the display of observed recharge numbers. Its
saved colour remains when the tool is off.

Native skill and effect drawing has a separate `nativeHudRendering` capability.
The local verifier checks its exact draw owners, traversal, and resource functions.
The transform rechecks those owners before it installs native HUD hooks. Core
and observation-only profiles preserve the original UI collection and destruction.
A changed drawing owner disables HUD presentation while leaving separately proved
skill, effect, and icon observations available to other consumers.

Disabled optional observers stop their domain reads. Core cursor observation
stays active. A small map-policy projection reads GWToolbox++'s PvP map flag
but keeps Guild Halls as an explicit gwonmac exception. PvP outposts close Tools
Expand Down
Loading
Loading