feat(control): инструмент «Маркер» на области видимости
Добавлена кисть маркера на пульте и презентации с настройками в панели эффектов; штрихи привязаны к жёлтой рамке, ластик и очистка работают с отдельным сессионным слоем. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
|
||||
import { SceneMarkerStore } from './sceneMarkerStore';
|
||||
|
||||
void test('SceneMarkerStore: сохраняет штрихи при переключении сцен', () => {
|
||||
const store = new SceneMarkerStore();
|
||||
store.switchScene('scene_a');
|
||||
store.dispatch({
|
||||
kind: 'stroke.add',
|
||||
stroke: {
|
||||
id: 'm1',
|
||||
seed: 1,
|
||||
createdAtMs: 100,
|
||||
points: [{ x: 0.5, y: 0.5, tMs: 100 }],
|
||||
radiusN: 0.08,
|
||||
color: '#ff0000',
|
||||
},
|
||||
});
|
||||
|
||||
store.switchScene('scene_b');
|
||||
assert.equal(store.getState().strokes.length, 0);
|
||||
|
||||
store.switchScene('scene_a');
|
||||
assert.equal(store.getState().strokes.length, 1);
|
||||
assert.equal(store.getState().strokes[0]?.id, 'm1');
|
||||
});
|
||||
|
||||
void test('SceneMarkerStore: resetSession очищает кэш', () => {
|
||||
const store = new SceneMarkerStore();
|
||||
store.switchScene('scene_a');
|
||||
store.dispatch({
|
||||
kind: 'stroke.add',
|
||||
stroke: {
|
||||
id: 'm1',
|
||||
seed: 1,
|
||||
createdAtMs: 100,
|
||||
points: [{ x: 0.2, y: 0.2, tMs: 100 }],
|
||||
radiusN: 0.08,
|
||||
color: '#00ff00',
|
||||
},
|
||||
});
|
||||
store.resetSession();
|
||||
store.switchScene('scene_a');
|
||||
assert.equal(store.getState().strokes.length, 0);
|
||||
});
|
||||
|
||||
void test('SceneMarkerStore: strokes.erase удаляет точки под ластиком', () => {
|
||||
const store = new SceneMarkerStore();
|
||||
store.switchScene('scene_a');
|
||||
store.dispatch({
|
||||
kind: 'stroke.add',
|
||||
stroke: {
|
||||
id: 'm1',
|
||||
seed: 1,
|
||||
createdAtMs: 100,
|
||||
points: [
|
||||
{ x: 0.1, y: 0.5, tMs: 100 },
|
||||
{ x: 0.5, y: 0.5, tMs: 101 },
|
||||
{ x: 0.9, y: 0.5, tMs: 102 },
|
||||
],
|
||||
radiusN: 0.04,
|
||||
color: '#ff0000',
|
||||
},
|
||||
});
|
||||
store.dispatch({
|
||||
kind: 'strokes.erase',
|
||||
points: [{ x: 0.5, y: 0.5, tMs: 200 }],
|
||||
radiusN: 0.06,
|
||||
});
|
||||
const strokes = store.getState().strokes;
|
||||
assert.ok(strokes.length >= 1);
|
||||
assert.ok(strokes.every((s) => s.points.every((p) => Math.abs(p.x - 0.5) > 0.05)));
|
||||
});
|
||||
|
||||
void test('SceneMarkerStore: strokes.clear удаляет все штрихи', () => {
|
||||
const store = new SceneMarkerStore();
|
||||
store.switchScene('scene_a');
|
||||
store.dispatch({
|
||||
kind: 'stroke.add',
|
||||
stroke: {
|
||||
id: 'm1',
|
||||
seed: 1,
|
||||
createdAtMs: 100,
|
||||
points: [{ x: 0.5, y: 0.5, tMs: 100 }],
|
||||
radiusN: 0.08,
|
||||
color: '#0000ff',
|
||||
},
|
||||
});
|
||||
store.dispatch({ kind: 'strokes.clear' });
|
||||
assert.equal(store.getState().strokes.length, 0);
|
||||
store.switchScene('scene_b');
|
||||
store.switchScene('scene_a');
|
||||
assert.equal(store.getState().strokes.length, 0);
|
||||
});
|
||||
Reference in New Issue
Block a user