Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8a80688
Merge pull request #2099 from VisActor/sync/main-1.1.5
xuefei1313 Jul 17, 2026
d101f62
docs: design Lynx native RAF scheduling
xuefei1313 Jul 24, 2026
f2494b2
docs: plan Lynx native RAF implementation
xuefei1313 Jul 24, 2026
8424a94
chore: ignore local worktrees
xuefei1313 Jul 24, 2026
de1dd3f
fix(lynx): prefer native animation frames
xuefei1313 Jul 24, 2026
dfae0a4
Merge pull request #2101 from VisActor/agent/use-native-lynx-raf
xuefei1313 Jul 24, 2026
4458b0d
fix(core): clear globalZIndex synchronously on state exit
xuefei1313 Jul 28, 2026
d9b9687
fix(core): preserve state exit transition defaults
xuefei1313 Jul 28, 2026
b06277a
fix(core): preserve target state attrs on exit
xuefei1313 Jul 28, 2026
1c7d00e
Merge pull request #2104 from VisActor/fix/global-z-index-state-clear
xuefei1313 Jul 28, 2026
f911862
test(core): cover negative rect outer border paths
xuefei1313 Jul 28, 2026
a046fa4
fix(core): normalize signed rect border bounds
xuefei1313 Jul 28, 2026
187decd
fix(core): resolve rect border fallback in attribute space
xuefei1313 Jul 28, 2026
cd83054
Merge pull request #2105 from VisActor/fix/rect-negative-size-outer-b…
xuefei1313 Jul 28, 2026
d696aa4
fix(axis): align rotated text OBB offsets
xuefei1313 Jul 29, 2026
7fb3d28
feat: support outerBorder / innerBorder for polygon graphic
g1f9 Jul 26, 2026
14afa6c
fix(polygon): align border bounds with stroke scale
xuefei1313 Jul 29, 2026
18e6b59
Merge pull request #2103 from g1f9/feat/polygon-outer-border
xuefei1313 Jul 29, 2026
aa66bd4
Merge pull request #2106 from VisActor/agent/fix-line-axis-obb-offset
xuefei1313 Jul 29, 2026
e1f2e62
build: prelease version 1.1.6
github-actions[bot] Jul 29, 2026
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,4 @@ docs/public/documents
spec-types
*.tsbuildinfo
.omx/
.worktrees/
36 changes: 18 additions & 18 deletions common/config/rush/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion common/config/rush/version-policies.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[{"definitionName":"lockStepVersion","policyName":"vrenderMain","version":"1.1.5","nextBump":"patch"}]
[{"definitionName":"lockStepVersion","policyName":"vrenderMain","version":"1.1.6","nextBump":"patch"}]
2 changes: 1 addition & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"@visactor/vchart": "1.3.0",
"@visactor/vutils": "~1.0.12",
"@visactor/vgrammar": "~0.5.7",
"@visactor/vrender": "workspace:1.1.5",
"@visactor/vrender": "workspace:1.1.6",
"markdown-it": "^13.0.0",
"highlight.js": "^11.8.0",
"axios": "^1.4.0",
Expand Down
199 changes: 199 additions & 0 deletions docs/superpowers/plans/2026-07-24-lynx-native-raf.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
# Lynx Native RAF Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Make the Lynx environment prefer the host's native animation-frame scheduler while preserving the existing timeout-backed fallback.

**Architecture:** Select and bind one request/cancel scheduler pair during `LynxEnvContribution.configure()`. The animation hot path reads stable cached functions, and incomplete native capability falls back atomically to `rafBasedSto`.

**Tech Stack:** TypeScript 4.9, Jest 26, Rush

## Global Constraints

- Native `requestAnimationFrame` and `cancelAnimationFrame` must be used only when both are functions.
- Native methods must retain the Lynx runtime as their `this` receiver.
- Missing or incomplete native capability must preserve the existing `rafBasedSto` behavior.
- Do not change ticker semantics or non-Lynx environments.
- Capability selection must stay out of the per-frame animation path.

---

### Task 1: Select the Lynx animation-frame scheduler pair

**Files:**
- Modify: `packages/vrender-kits/__tests__/unit/lynx-window-event.test.ts`
- Modify: `packages/vrender-kits/src/env/contributions/lynx-contribution.ts`

**Interfaces:**
- Consumes: `LynxEnvContribution.configure(service, params)`, `rafBasedSto.call(callback)`, and `rafBasedSto.clear(handle)`.
- Produces: `getRequestAnimationFrame(): (callback: FrameRequestCallback) => number` and `getCancelAnimationFrame(): (handle: number) => void`, backed by one scheduler pair selected during configuration.

- [ ] **Step 1: Add focused scheduler tests**

Add tests inside the existing `describe('lynx window event contribution', ...)` block:

```ts
test('uses the complete native lynx animation frame scheduler pair', () => {
const env = new LynxEnvContribution();
const service = {
env: 'lynx',
setActiveEnvContribution: jest.fn()
};
let requestReceiver: unknown;
let cancelReceiver: unknown;
let scheduledCallback: FrameRequestCallback;
let cancelledHandle: number;
const runtime = {
requestAnimationFrame(this: unknown, callback: FrameRequestCallback) {
requestReceiver = this;
scheduledCallback = callback;
return 17;
},
cancelAnimationFrame(this: unknown, handle: number) {
cancelReceiver = this;
cancelledHandle = handle;
}
};
const callback = jest.fn();

env.configure(service as any, { lynx: runtime });

expect(env.getRequestAnimationFrame()(callback)).toBe(17);
env.getCancelAnimationFrame()(17);

expect(requestReceiver).toBe(runtime);
expect(cancelReceiver).toBe(runtime);
expect(scheduledCallback).toBe(callback);
expect(cancelledHandle).toBe(17);
});

test('falls back as a pair when the native lynx scheduler is incomplete', () => {
jest.useFakeTimers();
try {
const env = new LynxEnvContribution();
const service = {
env: 'lynx',
setActiveEnvContribution: jest.fn()
};
const nativeRequest = jest.fn(() => 17);
const callback = jest.fn();

env.configure(service as any, {
lynx: {
requestAnimationFrame: nativeRequest
}
});

const handle = env.getRequestAnimationFrame()(callback);
env.getCancelAnimationFrame()(handle);
jest.runOnlyPendingTimers();

expect(nativeRequest).not.toHaveBeenCalled();
expect(callback).not.toHaveBeenCalled();
} finally {
jest.useRealTimers();
}
});
```

- [ ] **Step 2: Run the focused test and verify RED**

Run:

```bash
cd packages/vrender-kits
rushx test -- --runInBand __tests__/unit/lynx-window-event.test.ts
```

Expected: the native scheduler test fails because `getRequestAnimationFrame()` still schedules through `rafBasedSto`; the incomplete-scheduler fallback test passes.

- [ ] **Step 3: Implement scheduler selection**

Extend `LynxRuntime`:

```ts
requestAnimationFrame: (callback: FrameRequestCallback) => number;
cancelAnimationFrame: (handle: number) => void;
```

Add stable fallback functions near the Lynx runtime helpers:

```ts
const requestAnimationFrameBasedSTO = (callback: FrameRequestCallback): number => rafBasedSto.call(callback);
const cancelAnimationFrameBasedSTO = (handle: number): void => rafBasedSto.clear(handle);
```

Cache them on `LynxEnvContribution`:

```ts
private requestAnimationFrame = requestAnimationFrameBasedSTO;
private cancelAnimationFrame = cancelAnimationFrameBasedSTO;
```

After resolving `this.lynxRuntime` in `configure()`, atomically select the pair:

```ts
if (
typeof this.lynxRuntime?.requestAnimationFrame === 'function' &&
typeof this.lynxRuntime?.cancelAnimationFrame === 'function'
) {
this.requestAnimationFrame = this.lynxRuntime.requestAnimationFrame.bind(this.lynxRuntime);
this.cancelAnimationFrame = this.lynxRuntime.cancelAnimationFrame.bind(this.lynxRuntime);
} else {
this.requestAnimationFrame = requestAnimationFrameBasedSTO;
this.cancelAnimationFrame = cancelAnimationFrameBasedSTO;
}
```

Replace the legacy copied miniapp implementation:

```ts
getRequestAnimationFrame(): (callback: FrameRequestCallback) => number {
return this.requestAnimationFrame;
}

getCancelAnimationFrame(): (handle: number) => void {
return this.cancelAnimationFrame;
}
```

- [ ] **Step 4: Run the focused test and verify GREEN**

Run:

```bash
cd packages/vrender-kits
rushx test -- --runInBand __tests__/unit/lynx-window-event.test.ts
```

Expected: all tests in `lynx-window-event.test.ts` pass with no warnings or open handles.

- [ ] **Step 5: Run impacted-package and entry validation**

Run:

```bash
cd packages/vrender-kits
rushx test -- --runInBand
rushx compile
./node_modules/.bin/eslint src/env/contributions/lynx-contribution.ts __tests__/unit/lynx-window-event.test.ts
cd ../vrender
rushx test -- --runInBand __tests__/unit/entries.test.ts __tests__/unit/shared-app.test.ts
```

Expected: every command exits with status 0.

- [ ] **Step 6: Review and commit the implementation**

Run:

```bash
git diff --check
git diff -- packages/vrender-kits/src/env/contributions/lynx-contribution.ts packages/vrender-kits/__tests__/unit/lynx-window-event.test.ts
git status --short
git add packages/vrender-kits/src/env/contributions/lynx-contribution.ts packages/vrender-kits/__tests__/unit/lynx-window-event.test.ts
git diff --cached --check
git commit -m "fix(lynx): prefer native animation frames"
```

Expected: the commit contains only the Lynx scheduler implementation and its tests.
Loading
Loading