import { expect, test, useEditorSetupWithClear } from '#tests/e2e/fixtures' const editor = useEditorSetupWithClear('/?test&no-chrome&no-rulers') async function expectCanvas(name: string) { editor.canvas.assertNoErrors() const buffer = await editor.canvas.canvas.screenshot() expect(buffer).toMatchSnapshot(`${name}.png`) } test('drop shadow on white card', async () => { await editor.page.evaluate(() => { const store = window.openPencil?.getStore?.() if (!store) throw new Error('OpenPencil store not initialized') const pageId = store.state.currentPageId store.graph.createNode('FRAME', pageId, { name: 'Card', x: 80, y: 80, width: 200, height: 120, cornerRadius: 12, fills: [{ type: 'SOLID', color: { r: 1, g: 1, b: 1, a: 1 }, visible: true, opacity: 1 }], effects: [ { type: 'DROP_SHADOW', color: { r: 0, g: 0, b: 0, a: 0.25 }, offset: { x: 0, y: 4 }, radius: 16, spread: 0, visible: true } ] }) store.clearSelection() store.requestRender() }) await editor.canvas.waitForRender() await expectCanvas('drop-shadow-white-card') }) test('drop shadow with spread', async () => { await editor.page.evaluate(() => { const store = window.openPencil?.getStore?.() if (!store) throw new Error('OpenPencil store not initialized') const pageId = store.state.currentPageId store.graph.createNode('FRAME', pageId, { name: 'Card', x: 80, y: 80, width: 200, height: 120, cornerRadius: 12, fills: [{ type: 'SOLID', color: { r: 1, g: 1, b: 1, a: 1 }, visible: true, opacity: 1 }], effects: [ { type: 'DROP_SHADOW', color: { r: 0.23, g: 0.51, b: 0.96, a: 0.3 }, offset: { x: 0, y: 4 }, radius: 12, spread: 8, visible: true } ] }) store.clearSelection() store.requestRender() }) await editor.canvas.waitForRender() await expectCanvas('drop-shadow-with-spread') }) test('inner shadow', async () => { await editor.page.evaluate(() => { const store = window.openPencil?.getStore?.() if (!store) throw new Error('OpenPencil store not initialized') const pageId = store.state.currentPageId store.graph.createNode('FRAME', pageId, { name: 'Card', x: 80, y: 80, width: 200, height: 120, cornerRadius: 12, fills: [ { type: 'SOLID', color: { r: 0.96, g: 0.96, b: 0.97, a: 1 }, visible: true, opacity: 1 } ], effects: [ { type: 'INNER_SHADOW', color: { r: 0, g: 0, b: 0, a: 0.15 }, offset: { x: 0, y: 2 }, radius: 8, spread: 0, visible: true } ] }) store.clearSelection() store.requestRender() }) await editor.canvas.waitForRender() await expectCanvas('inner-shadow') }) test('inner shadow with spread', async () => { await editor.page.evaluate(() => { const store = window.openPencil?.getStore?.() if (!store) throw new Error('OpenPencil store not initialized') const pageId = store.state.currentPageId store.graph.createNode('FRAME', pageId, { name: 'Card', x: 80, y: 80, width: 200, height: 120, cornerRadius: 12, fills: [ { type: 'SOLID', color: { r: 0.96, g: 0.96, b: 0.97, a: 1 }, visible: true, opacity: 1 } ], effects: [ { type: 'INNER_SHADOW', color: { r: 0, g: 0, b: 0, a: 0.2 }, offset: { x: 0, y: 2 }, radius: 8, spread: 4, visible: true } ] }) store.clearSelection() store.requestRender() }) await editor.canvas.waitForRender() await expectCanvas('inner-shadow-with-spread') }) test('blend modes', async () => { await editor.page.evaluate(() => { const store = window.openPencil?.getStore?.() if (!store) throw new Error('OpenPencil store not initialized') const pageId = store.state.currentPageId store.graph.createNode('FRAME', pageId, { name: 'Blend Backdrop', x: 64, y: 64, width: 324, height: 180, cornerRadius: 20, fills: [ { type: 'SOLID', color: { r: 0.95, g: 0.95, b: 0.97, a: 1 }, visible: true, opacity: 1 } ] }) store.graph.createNode('RECTANGLE', pageId, { name: 'Multiply Base', x: 96, y: 96, width: 96, height: 96, cornerRadius: 20, fills: [ { type: 'SOLID', color: { r: 1, g: 0.23, b: 0.2, a: 0.95 }, visible: true, opacity: 1 } ] }) store.graph.createNode('RECTANGLE', pageId, { name: 'Multiply Layer', x: 144, y: 96, width: 96, height: 96, cornerRadius: 20, blendMode: 'MULTIPLY', fills: [ { type: 'SOLID', color: { r: 0.12, g: 0.45, b: 1, a: 0.92 }, visible: true, opacity: 1 } ] }) store.graph.createNode('ELLIPSE', pageId, { name: 'Screen Layer', x: 212, y: 92, width: 104, height: 104, blendMode: 'SCREEN', fills: [ { type: 'SOLID', color: { r: 0.05, g: 0.75, b: 0.45, a: 0.8 }, visible: true, opacity: 1 } ] }) store.graph.createNode('RECTANGLE', pageId, { name: 'Overlay Multi Fill', x: 280, y: 112, width: 56, height: 56, cornerRadius: 14, fills: [ { type: 'SOLID', color: { r: 0.98, g: 0.75, b: 0.18, a: 1 }, visible: true, opacity: 1 }, { type: 'SOLID', color: { r: 0.58, g: 0.27, b: 0.95, a: 0.86 }, visible: true, opacity: 1, blendMode: 'OVERLAY' } ] }) store.clearSelection() store.requestRender() }) await editor.canvas.waitForRender() await expectCanvas('blend-modes') }) test('alpha mask stack', async () => { await editor.page.evaluate(() => { const store = window.openPencil?.getStore?.() if (!store) throw new Error('OpenPencil store not initialized') const pageId = store.state.currentPageId const frame = store.graph.createNode('FRAME', pageId, { name: 'Mask Backdrop', x: 64, y: 64, width: 324, height: 180, cornerRadius: 20, fills: [ { type: 'SOLID', color: { r: 0.08, g: 0.1, b: 0.18, a: 1 }, visible: true, opacity: 1 } ] }) store.graph.createNode('RECTANGLE', frame.id, { name: 'Unmasked Baseline', x: 24, y: 24, width: 58, height: 132, cornerRadius: 12, fills: [ { type: 'SOLID', color: { r: 0.98, g: 0.75, b: 0.18, a: 1 }, visible: true, opacity: 1 } ] }) store.graph.createNode('ELLIPSE', frame.id, { name: 'Alpha Mask', x: 104, y: 28, width: 152, height: 112, isMask: true, maskType: 'ALPHA', fills: [{ type: 'SOLID', color: { r: 1, g: 1, b: 1, a: 1 }, visible: true, opacity: 1 }] }) store.graph.createNode('RECTANGLE', frame.id, { name: 'Masked Cyan Stripe', x: 78, y: 34, width: 220, height: 38, rotation: -12, fills: [ { type: 'SOLID', color: { r: 0.08, g: 0.73, b: 0.73, a: 1 }, visible: true, opacity: 1 } ] }) store.graph.createNode('RECTANGLE', frame.id, { name: 'Masked Purple Stripe', x: 88, y: 86, width: 222, height: 42, rotation: -12, fills: [ { type: 'SOLID', color: { r: 0.58, g: 0.27, b: 0.95, a: 1 }, visible: true, opacity: 1 } ] }) store.graph.createNode('RECTANGLE', frame.id, { name: 'Masked Pink Stripe', x: 98, y: 136, width: 222, height: 42, rotation: -12, fills: [{ type: 'SOLID', color: { r: 1, g: 0.23, b: 0.43, a: 1 }, visible: true, opacity: 1 }] }) store.clearSelection() store.requestRender() }) await editor.canvas.waitForRender() await expectCanvas('alpha-mask-stack') }) test('smoothed corners with blended shadow', async () => { await editor.page.evaluate(() => { const store = window.openPencil?.getStore?.() if (!store) throw new Error('OpenPencil store not initialized') const pageId = store.state.currentPageId store.graph.createNode('FRAME', pageId, { name: 'Smooth Rectangle Backdrop', x: 64, y: 64, width: 272, height: 168, cornerRadius: 20, fills: [ { type: 'SOLID', color: { r: 0.08, g: 0.1, b: 0.18, a: 1 }, visible: true, opacity: 1 } ] }) store.graph.createNode('RECTANGLE', pageId, { name: 'Uniform Smooth Radius', x: 92, y: 92, width: 112, height: 88, cornerRadius: 28, cornerSmoothing: 0.75, fills: [ { type: 'SOLID', color: { r: 0.58, g: 0.27, b: 0.95, a: 1 }, visible: true, opacity: 1 } ], effects: [ { type: 'DROP_SHADOW', color: { r: 0.56, g: 0.33, b: 1, a: 0.72 }, offset: { x: 0, y: 0 }, radius: 28, spread: 0, blendMode: 'SCREEN', visible: true } ] }) store.graph.createNode('RECTANGLE', pageId, { name: 'Independent Smooth Radius', x: 212, y: 92, width: 92, height: 88, independentCorners: true, topLeftRadius: 34, topRightRadius: 10, bottomRightRadius: 34, bottomLeftRadius: 10, cornerSmoothing: 1, fills: [ { type: 'SOLID', color: { r: 0.08, g: 0.73, b: 0.73, a: 1 }, visible: true, opacity: 1 } ], strokes: [ { color: { r: 1, g: 1, b: 1, a: 0.8 }, weight: 2, visible: true, opacity: 1, align: 'INSIDE' } ], effects: [ { type: 'INNER_SHADOW', color: { r: 0, g: 0, b: 0, a: 0.28 }, offset: { x: 0, y: 3 }, radius: 8, spread: 0, visible: true } ] }) store.clearSelection() store.requestRender() }) await editor.canvas.waitForRender() await expectCanvas('smoothed-corners-with-blended-shadow') }) test('drop shadow on ellipse', async () => { await editor.page.evaluate(() => { const store = window.openPencil?.getStore?.() if (!store) throw new Error('OpenPencil store not initialized') const pageId = store.state.currentPageId store.graph.createNode('ELLIPSE', pageId, { name: 'Circle', x: 100, y: 80, width: 160, height: 160, fills: [ { type: 'SOLID', color: { r: 0.38, g: 0.35, b: 0.95, a: 1 }, visible: true, opacity: 1 } ], effects: [ { type: 'DROP_SHADOW', color: { r: 0, g: 0, b: 0, a: 0.3 }, offset: { x: 0, y: 6 }, radius: 20, spread: 0, visible: true } ] }) store.clearSelection() store.requestRender() }) await editor.canvas.waitForRender() await expectCanvas('drop-shadow-ellipse') }) test('combined drop and inner shadow', async () => { await editor.page.evaluate(() => { const store = window.openPencil?.getStore?.() if (!store) throw new Error('OpenPencil store not initialized') const pageId = store.state.currentPageId store.graph.createNode('FRAME', pageId, { name: 'Card', x: 80, y: 80, width: 200, height: 120, cornerRadius: 12, fills: [{ type: 'SOLID', color: { r: 1, g: 1, b: 1, a: 1 }, visible: true, opacity: 1 }], effects: [ { type: 'DROP_SHADOW', color: { r: 0, g: 0, b: 0, a: 0.15 }, offset: { x: 0, y: 4 }, radius: 16, spread: 0, visible: true }, { type: 'INNER_SHADOW', color: { r: 0, g: 0, b: 0, a: 0.08 }, offset: { x: 0, y: 1 }, radius: 2, spread: 0, visible: true } ] }) store.clearSelection() store.requestRender() }) await editor.canvas.waitForRender() await expectCanvas('combined-drop-inner-shadow') }) test('text drop shadow on glyphs', async () => { await editor.page.evaluate(() => { const store = window.openPencil?.getStore?.() if (!store) throw new Error('OpenPencil store not initialized') const pageId = store.state.currentPageId store.graph.createNode('TEXT', pageId, { name: 'Shadow Text', x: 60, y: 120, width: 300, height: 50, text: 'Shadow', fontSize: 40, fontWeight: 700, fontFamily: 'Inter', fills: [{ type: 'SOLID', color: { r: 0, g: 0, b: 0, a: 1 }, visible: true, opacity: 1 }], effects: [ { type: 'DROP_SHADOW', color: { r: 0.23, g: 0.51, b: 0.96, a: 0.6 }, offset: { x: 3, y: 3 }, radius: 6, spread: 0, visible: true } ] }) store.clearSelection() store.requestRender() }) await editor.canvas.waitForRender() await editor.page.waitForTimeout(500) await editor.canvas.waitForRender() await expectCanvas('text-drop-shadow') }) test('layer blur', async () => { await editor.page.evaluate(() => { const store = window.openPencil?.getStore?.() if (!store) throw new Error('OpenPencil store not initialized') const pageId = store.state.currentPageId store.graph.createNode('RECTANGLE', pageId, { name: 'Blurred', x: 80, y: 80, width: 200, height: 120, cornerRadius: 12, fills: [ { type: 'SOLID', color: { r: 0.23, g: 0.51, b: 0.96, a: 1 }, visible: true, opacity: 1 } ], effects: [ { type: 'LAYER_BLUR', color: { r: 0, g: 0, b: 0, a: 0 }, offset: { x: 0, y: 0 }, radius: 8, spread: 0, visible: true } ] }) store.clearSelection() store.requestRender() }) await editor.canvas.waitForRender() await expectCanvas('layer-blur') }) test('invisible effect has no visual impact', async () => { await editor.page.evaluate(() => { const store = window.openPencil?.getStore?.() if (!store) throw new Error('OpenPencil store not initialized') const pageId = store.state.currentPageId store.graph.createNode('FRAME', pageId, { name: 'Card', x: 80, y: 80, width: 200, height: 120, cornerRadius: 12, fills: [{ type: 'SOLID', color: { r: 1, g: 1, b: 1, a: 1 }, visible: true, opacity: 1 }], effects: [ { type: 'DROP_SHADOW', color: { r: 0, g: 0, b: 0, a: 0.5 }, offset: { x: 0, y: 8 }, radius: 24, spread: 0, visible: false } ] }) store.clearSelection() store.requestRender() }) await editor.canvas.waitForRender() await expectCanvas('invisible-effect') })