@pinepaper.studio/mcp-server 1.5.1 → 1.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/agent/types.d.ts +6 -6
  2. package/dist/browser/puppeteer-controller.d.ts +5 -1
  3. package/dist/browser/puppeteer-controller.d.ts.map +1 -1
  4. package/dist/browser/puppeteer-controller.js +11 -3
  5. package/dist/browser/puppeteer-controller.js.map +1 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +80 -106
  8. package/dist/index.js.map +1 -1
  9. package/dist/ontology/design-graph.d.ts +85 -0
  10. package/dist/ontology/design-graph.d.ts.map +1 -0
  11. package/dist/ontology/design-graph.js +944 -0
  12. package/dist/ontology/design-graph.js.map +1 -0
  13. package/dist/ontology/index.d.ts +11 -0
  14. package/dist/ontology/index.d.ts.map +1 -0
  15. package/dist/ontology/index.js +14 -0
  16. package/dist/ontology/index.js.map +1 -0
  17. package/dist/ontology/semantic-vocabulary.d.ts +12 -0
  18. package/dist/ontology/semantic-vocabulary.d.ts.map +1 -0
  19. package/dist/ontology/semantic-vocabulary.js +26 -0
  20. package/dist/ontology/semantic-vocabulary.js.map +1 -0
  21. package/dist/ontology/types.d.ts +255 -0
  22. package/dist/ontology/types.d.ts.map +1 -0
  23. package/dist/ontology/types.js +10 -0
  24. package/dist/ontology/types.js.map +1 -0
  25. package/dist/ontology/validator.d.ts +36 -0
  26. package/dist/ontology/validator.d.ts.map +1 -0
  27. package/dist/ontology/validator.js +374 -0
  28. package/dist/ontology/validator.js.map +1 -0
  29. package/dist/ontology/vocabulary.d.ts +34 -0
  30. package/dist/ontology/vocabulary.d.ts.map +1 -0
  31. package/dist/ontology/vocabulary.js +395 -0
  32. package/dist/ontology/vocabulary.js.map +1 -0
  33. package/dist/tools/compact-descriptions.d.ts +2 -2
  34. package/dist/tools/compact-descriptions.d.ts.map +1 -1
  35. package/dist/tools/compact-descriptions.js +45 -233
  36. package/dist/tools/compact-descriptions.js.map +1 -1
  37. package/dist/tools/definitions.d.ts +1 -1
  38. package/dist/tools/definitions.d.ts.map +1 -1
  39. package/dist/tools/definitions.js +638 -31
  40. package/dist/tools/definitions.js.map +1 -1
  41. package/dist/tools/handlers.d.ts.map +1 -1
  42. package/dist/tools/handlers.js +290 -145
  43. package/dist/tools/handlers.js.map +1 -1
  44. package/dist/tools/minimal-descriptions.d.ts.map +1 -1
  45. package/dist/tools/minimal-descriptions.js +22 -2
  46. package/dist/tools/minimal-descriptions.js.map +1 -1
  47. package/dist/tools/toolkits.d.ts.map +1 -1
  48. package/dist/tools/toolkits.js +31 -1
  49. package/dist/tools/toolkits.js.map +1 -1
  50. package/dist/types/code-generator.d.ts +14 -2
  51. package/dist/types/code-generator.d.ts.map +1 -1
  52. package/dist/types/code-generator.js +635 -6
  53. package/dist/types/code-generator.js.map +1 -1
  54. package/dist/types/schemas.d.ts +387 -82
  55. package/dist/types/schemas.d.ts.map +1 -1
  56. package/dist/types/schemas.js +136 -2
  57. package/dist/types/schemas.js.map +1 -1
  58. package/package.json +2 -2
@@ -351,6 +351,12 @@ function generatePlayTimelineCode(action, duration, loop, time) {
351
351
  // Play keyframe timeline
352
352
  app.playKeyframeTimeline(${duration || 5}, ${loop ?? false});
353
353
  ({ success: true, action: 'play', duration: ${duration || 5}, loop: ${loop ?? false} });
354
+ `.trim();
355
+ case 'pause':
356
+ return `
357
+ // Pause keyframe timeline
358
+ app.pauseKeyframeTimeline();
359
+ ({ success: true, action: 'pause' });
354
360
  `.trim();
355
361
  case 'stop':
356
362
  return `
@@ -1796,11 +1802,11 @@ return { success: true, action: 'seek', time: ${op.time || 0} };
1796
1802
  const validated = AgentExportInputSchema.parse(input);
1797
1803
  const { platform, format, quality } = validated;
1798
1804
  const qualityLevel = quality || 'standard';
1799
- // Quality settings
1805
+ // Quality settings (bitrate in bps for VideoEncoder)
1800
1806
  const qualitySettings = {
1801
- draft: { compression: 0.6, fps: 15, dpi: 72 },
1802
- standard: { compression: 0.85, fps: 30, dpi: 150 },
1803
- high: { compression: 0.95, fps: 60, dpi: 300 },
1807
+ draft: { compression: 0.6, fps: 15, dpi: 72, bitrate: 2_000_000 },
1808
+ standard: { compression: 0.85, fps: 30, dpi: 150, bitrate: 5_000_000 },
1809
+ high: { compression: 0.95, fps: 60, dpi: 300, bitrate: 8_000_000 },
1804
1810
  }[qualityLevel];
1805
1811
  // Platform presets
1806
1812
  const platformPresets = {
@@ -1877,7 +1883,7 @@ return { success: true, action: 'seek', time: ${op.time || 0} };
1877
1883
  const videoMimeType = { mp4: 'video/mp4', webm: 'video/webm', gif: 'image/gif' }[format];
1878
1884
  // Use _quickExportVideo (delegates to VideoExporter.export internally)
1879
1885
  if (app.exportEngine && app.exportEngine._quickExportVideo) {
1880
- const videoResult = await app.exportEngine._quickExportVideo(format, { fps: settings.fps, duration: 5 }, false);
1886
+ const videoResult = await app.exportEngine._quickExportVideo(format, { fps: settings.fps, bitrate: settings.bitrate, duration: 5 }, false);
1881
1887
  if (videoResult && videoResult.blob) {
1882
1888
  const reader = new FileReader();
1883
1889
  const dataUrl = await new Promise(resolve => {
@@ -1890,7 +1896,7 @@ return { success: true, action: 'seek', time: ${op.time || 0} };
1890
1896
  }
1891
1897
  } else if (app.exportEngine && app.exportEngine.videoExporter) {
1892
1898
  // Fallback: call VideoExporter.export directly
1893
- const blob = await app.exportEngine.videoExporter.export({ format, fps: settings.fps, duration: 5 });
1899
+ const blob = await app.exportEngine.videoExporter.export({ format, fps: settings.fps, bitrate: settings.bitrate, duration: 5 });
1894
1900
  const reader = new FileReader();
1895
1901
  const dataUrl = await new Promise(resolve => {
1896
1902
  reader.onloadend = () => resolve(reader.result);
@@ -3465,6 +3471,629 @@ ${mask ? ` app.imageTools.applyMask(raster, '${mask}');\n` : ''} const ite
3465
3471
  })();
3466
3472
  `.trim();
3467
3473
  }
3474
+ generateManageScenes(input) {
3475
+ const guard = `if (!app.sceneManager) return { error: 'SceneManager not available' };`;
3476
+ switch (input.action) {
3477
+ case 'save':
3478
+ return `
3479
+ // Save current canvas as scene
3480
+ (async function() {
3481
+ ${guard}
3482
+ try {
3483
+ const result = await app.sceneManager.saveCurrentAsScene(${JSON.stringify(input.name || 'Untitled Scene')});
3484
+ return { success: true, action: 'save', sceneId: result?.id || result, name: ${JSON.stringify(input.name || 'Untitled Scene')} };
3485
+ } catch (e) {
3486
+ return { error: 'Failed to save scene: ' + e.message };
3487
+ }
3488
+ })();
3489
+ `.trim();
3490
+ case 'load':
3491
+ return `
3492
+ // Load scene
3493
+ (async function() {
3494
+ ${guard}
3495
+ try {
3496
+ await app.sceneManager.loadScene(${JSON.stringify(input.sceneId)}${input.transition ? `, { transition: ${JSON.stringify(input.transition)} }` : ''});
3497
+ return { success: true, action: 'load', sceneId: ${JSON.stringify(input.sceneId)}${input.transition ? `, transition: ${JSON.stringify(input.transition)}` : ''} };
3498
+ } catch (e) {
3499
+ return { error: 'Failed to load scene: ' + e.message };
3500
+ }
3501
+ })();
3502
+ `.trim();
3503
+ case 'list':
3504
+ return `
3505
+ // List all scenes
3506
+ (function() {
3507
+ ${guard}
3508
+ const scenes = app.sceneManager.listScenes();
3509
+ return { success: true, action: 'list', scenes: scenes, count: scenes.length };
3510
+ })();
3511
+ `.trim();
3512
+ case 'delete':
3513
+ return `
3514
+ // Delete scene
3515
+ (function() {
3516
+ ${guard}
3517
+ app.sceneManager.deleteScene(${JSON.stringify(input.sceneId)});
3518
+ return { success: true, action: 'delete', sceneId: ${JSON.stringify(input.sceneId)} };
3519
+ })();
3520
+ `.trim();
3521
+ case 'rename':
3522
+ return `
3523
+ // Rename scene
3524
+ (function() {
3525
+ ${guard}
3526
+ app.sceneManager.renameScene(${JSON.stringify(input.sceneId)}, ${JSON.stringify(input.name)});
3527
+ return { success: true, action: 'rename', sceneId: ${JSON.stringify(input.sceneId)}, name: ${JSON.stringify(input.name)} };
3528
+ })();
3529
+ `.trim();
3530
+ case 'duplicate':
3531
+ return `
3532
+ // Duplicate scene
3533
+ (function() {
3534
+ ${guard}
3535
+ const result = app.sceneManager.duplicateScene(${JSON.stringify(input.sceneId)});
3536
+ return { success: true, action: 'duplicate', originalId: ${JSON.stringify(input.sceneId)}, newScene: result };
3537
+ })();
3538
+ `.trim();
3539
+ case 'reorder':
3540
+ return `
3541
+ // Reorder scenes
3542
+ (function() {
3543
+ ${guard}
3544
+ app.sceneManager.reorderScenes(${JSON.stringify(input.sceneIds)});
3545
+ return { success: true, action: 'reorder', order: ${JSON.stringify(input.sceneIds)} };
3546
+ })();
3547
+ `.trim();
3548
+ case 'info':
3549
+ return `
3550
+ // Get scene info
3551
+ (function() {
3552
+ ${guard}
3553
+ const scene = app.sceneManager.getScene(${JSON.stringify(input.sceneId)});
3554
+ if (!scene) return { error: 'Scene not found: ${input.sceneId}' };
3555
+ return { success: true, action: 'info', scene: scene };
3556
+ })();
3557
+ `.trim();
3558
+ case 'export':
3559
+ return `
3560
+ // Export all scenes
3561
+ (function() {
3562
+ ${guard}
3563
+ const data = app.sceneManager.exportScenes();
3564
+ return { success: true, action: 'export', data: data };
3565
+ })();
3566
+ `.trim();
3567
+ case 'import':
3568
+ return `
3569
+ // Import scenes
3570
+ (function() {
3571
+ ${guard}
3572
+ try {
3573
+ const json = ${JSON.stringify(input.scenesJson)};
3574
+ app.sceneManager.importScenes(json${input.merge !== undefined ? `, { merge: ${input.merge} }` : ''});
3575
+ return { success: true, action: 'import'${input.merge !== undefined ? `, merge: ${input.merge}` : ''} };
3576
+ } catch (e) {
3577
+ return { error: 'Failed to import scenes: ' + e.message };
3578
+ }
3579
+ })();
3580
+ `.trim();
3581
+ default:
3582
+ return `(function() { return { error: 'Unknown manage_scenes action: ${input.action}' }; })();`;
3583
+ }
3584
+ }
3585
+ generateScenePlayback(input) {
3586
+ const guard = `if (!app.sceneManager) return { error: 'SceneManager not available' };`;
3587
+ switch (input.action) {
3588
+ case 'create_chain': {
3589
+ const opts = [];
3590
+ if (input.loop !== undefined)
3591
+ opts.push(`loop: ${input.loop}`);
3592
+ if (input.autoPlay !== undefined)
3593
+ opts.push(`autoPlay: ${input.autoPlay}`);
3594
+ if (input.defaultDuration !== undefined)
3595
+ opts.push(`defaultDuration: ${input.defaultDuration * 1000}`);
3596
+ if (input.defaultTransition !== undefined)
3597
+ opts.push(`defaultTransition: ${JSON.stringify(input.defaultTransition)}`);
3598
+ if (input.transitionDuration !== undefined)
3599
+ opts.push(`transitionDuration: ${input.transitionDuration * 1000}`);
3600
+ const optsStr = opts.length > 0 ? `, { ${opts.join(', ')} }` : '';
3601
+ return `
3602
+ // Create scene chain for sequential playback
3603
+ (function() {
3604
+ ${guard}
3605
+ app.sceneManager.createChain(${JSON.stringify(input.sceneIds)}${optsStr});
3606
+ return { success: true, action: 'create_chain', sceneIds: ${JSON.stringify(input.sceneIds)}${input.loop !== undefined ? `, loop: ${input.loop}` : ''}${input.defaultDuration !== undefined ? `, defaultDuration: ${input.defaultDuration}` : ''} };
3607
+ })();
3608
+ `.trim();
3609
+ }
3610
+ case 'play':
3611
+ return `
3612
+ // Play scene chain
3613
+ (async function() {
3614
+ ${guard}
3615
+ try {
3616
+ await app.sceneManager.playChain();
3617
+ return { success: true, action: 'play' };
3618
+ } catch (e) {
3619
+ return { error: 'Failed to play chain: ' + e.message };
3620
+ }
3621
+ })();
3622
+ `.trim();
3623
+ case 'pause':
3624
+ return `
3625
+ // Pause scene chain
3626
+ (function() {
3627
+ ${guard}
3628
+ app.sceneManager.pauseChain();
3629
+ return { success: true, action: 'pause' };
3630
+ })();
3631
+ `.trim();
3632
+ case 'resume':
3633
+ return `
3634
+ // Resume scene chain
3635
+ (function() {
3636
+ ${guard}
3637
+ app.sceneManager.resumeChain();
3638
+ return { success: true, action: 'resume' };
3639
+ })();
3640
+ `.trim();
3641
+ case 'stop':
3642
+ return `
3643
+ // Stop scene chain
3644
+ (function() {
3645
+ ${guard}
3646
+ app.sceneManager.stopChain();
3647
+ return { success: true, action: 'stop' };
3648
+ })();
3649
+ `.trim();
3650
+ case 'toggle_loop':
3651
+ return `
3652
+ // Toggle loop mode
3653
+ (function() {
3654
+ ${guard}
3655
+ app.sceneManager.setLoop(${input.enabled ?? true});
3656
+ return { success: true, action: 'toggle_loop', enabled: ${input.enabled ?? true} };
3657
+ })();
3658
+ `.trim();
3659
+ case 'jump':
3660
+ return `
3661
+ // Jump to scene index
3662
+ (async function() {
3663
+ ${guard}
3664
+ try {
3665
+ await app.sceneManager.jumpToChainIndex(${input.index ?? 0});
3666
+ return { success: true, action: 'jump', index: ${input.index ?? 0} };
3667
+ } catch (e) {
3668
+ return { error: 'Failed to jump to index: ' + e.message };
3669
+ }
3670
+ })();
3671
+ `.trim();
3672
+ default:
3673
+ return `(function() { return { error: 'Unknown scene_playback action: ${input.action}' }; })();`;
3674
+ }
3675
+ }
3676
+ // ===========================================================================
3677
+ // SELECTION, TRANSFORM & HISTORY
3678
+ // ===========================================================================
3679
+ generateSelection(input) {
3680
+ switch (input.action) {
3681
+ case 'select': {
3682
+ const ids = JSON.stringify(input.itemIds || []);
3683
+ const mode = input.mode || 'replace';
3684
+ return `
3685
+ // Select items
3686
+ (function() {
3687
+ const ids = ${ids};
3688
+ if (ids.length === 0) return { error: 'No itemIds provided' };
3689
+ ${mode === 'replace' ? 'app.deselectAll();' : ''}
3690
+ const selected = [];
3691
+ for (const id of ids) {
3692
+ const entry = app.itemRegistry.get(id);
3693
+ if (entry && entry.item) {
3694
+ ${mode === 'remove' ? 'entry.item.selected = false;' : 'app.select(entry.item);'}
3695
+ selected.push(id);
3696
+ }
3697
+ }
3698
+ return { success: true, action: 'select', mode: '${mode}', selected };
3699
+ })();`.trim();
3700
+ }
3701
+ case 'select_all':
3702
+ return `
3703
+ // Select all items
3704
+ (function() {
3705
+ app.selectAll();
3706
+ const items = app.getSelection().map(i => i.data?.itemId || i.name || i.id);
3707
+ return { success: true, action: 'select_all', count: items.length, items };
3708
+ })();`.trim();
3709
+ case 'deselect_all':
3710
+ return `
3711
+ // Deselect all items
3712
+ (function() {
3713
+ app.deselectAll();
3714
+ return { success: true, action: 'deselect_all' };
3715
+ })();`.trim();
3716
+ case 'get':
3717
+ return `
3718
+ // Get current selection
3719
+ (function() {
3720
+ const items = app.getSelection().map(i => ({
3721
+ itemId: i.data?.itemId || i.name || i.id,
3722
+ type: i.data?.itemType || i.className,
3723
+ bounds: i.bounds ? { x: i.bounds.x, y: i.bounds.y, width: i.bounds.width, height: i.bounds.height } : null
3724
+ }));
3725
+ return { success: true, action: 'get', count: items.length, items };
3726
+ })();`.trim();
3727
+ case 'delete_selected':
3728
+ return `
3729
+ // Delete selected items
3730
+ (function() {
3731
+ const selection = app.getSelection();
3732
+ const deleted = selection.map(i => i.data?.itemId || i.name || i.id);
3733
+ app.deleteSelected();
3734
+ return { success: true, action: 'delete_selected', deleted, count: deleted.length };
3735
+ })();`.trim();
3736
+ default:
3737
+ return `(function() { return { error: 'Unknown selection action: ${input.action}' }; })();`;
3738
+ }
3739
+ }
3740
+ generateTransform(input) {
3741
+ switch (input.action) {
3742
+ case 'nudge': {
3743
+ const dx = input.dx ?? 0;
3744
+ const dy = input.dy ?? 0;
3745
+ return `
3746
+ // Nudge item position
3747
+ (function() {
3748
+ const entry = app.itemRegistry.get(${JSON.stringify(input.itemId || '')});
3749
+ if (!entry || !entry.item) return { error: 'Item not found: ${input.itemId}' };
3750
+ entry.item.position.x += ${dx};
3751
+ entry.item.position.y += ${dy};
3752
+ return { success: true, action: 'nudge', itemId: '${input.itemId}', dx: ${dx}, dy: ${dy}, position: { x: entry.item.position.x, y: entry.item.position.y } };
3753
+ })();`.trim();
3754
+ }
3755
+ case 'flip': {
3756
+ const dir = input.direction || 'horizontal';
3757
+ return `
3758
+ // Flip item ${dir}ly
3759
+ (function() {
3760
+ const entry = app.itemRegistry.get(${JSON.stringify(input.itemId || '')});
3761
+ if (!entry || !entry.item) return { error: 'Item not found: ${input.itemId}' };
3762
+ ${dir === 'horizontal' ? 'entry.item.scale(-1, 1);' : 'entry.item.scale(1, -1);'}
3763
+ return { success: true, action: 'flip', itemId: '${input.itemId}', direction: '${dir}' };
3764
+ })();`.trim();
3765
+ }
3766
+ case 'reorder': {
3767
+ const order = input.order || 'bringToFront';
3768
+ const methodMap = {
3769
+ bringToFront: 'bringToFront',
3770
+ sendToBack: 'sendToBack',
3771
+ moveUp: 'moveAbove',
3772
+ moveDown: 'moveBelow',
3773
+ };
3774
+ const method = methodMap[order] || 'bringToFront';
3775
+ const needsSibling = order === 'moveUp' || order === 'moveDown';
3776
+ if (needsSibling) {
3777
+ const siblingExpr = order === 'moveUp' ? 'entry.item.nextSibling' : 'entry.item.previousSibling';
3778
+ return `
3779
+ // Reorder item: ${order}
3780
+ (function() {
3781
+ const entry = app.itemRegistry.get(${JSON.stringify(input.itemId || '')});
3782
+ if (!entry || !entry.item) return { error: 'Item not found: ${input.itemId}' };
3783
+ const sibling = ${siblingExpr};
3784
+ if (sibling) entry.item.${method}(sibling);
3785
+ return { success: true, action: 'reorder', itemId: '${input.itemId}', order: '${order}' };
3786
+ })();`.trim();
3787
+ }
3788
+ return `
3789
+ // Reorder item: ${order}
3790
+ (function() {
3791
+ const entry = app.itemRegistry.get(${JSON.stringify(input.itemId || '')});
3792
+ if (!entry || !entry.item) return { error: 'Item not found: ${input.itemId}' };
3793
+ entry.item.${method}();
3794
+ return { success: true, action: 'reorder', itemId: '${input.itemId}', order: '${order}' };
3795
+ })();`.trim();
3796
+ }
3797
+ default:
3798
+ return `(function() { return { error: 'Unknown transform action: ${input.action}' }; })();`;
3799
+ }
3800
+ }
3801
+ generateHistory(input) {
3802
+ const guard = `if (!app.historyManager) return { error: 'HistoryManager not available' };`;
3803
+ switch (input.action) {
3804
+ case 'undo':
3805
+ return `
3806
+ // Undo last action
3807
+ (function() {
3808
+ ${guard}
3809
+ app.historyManager.undo();
3810
+ return { success: true, action: 'undo' };
3811
+ })();`.trim();
3812
+ case 'redo':
3813
+ return `
3814
+ // Redo last undone action
3815
+ (function() {
3816
+ ${guard}
3817
+ app.historyManager.redo();
3818
+ return { success: true, action: 'redo' };
3819
+ })();`.trim();
3820
+ case 'get_state':
3821
+ return `
3822
+ // Get history state
3823
+ (function() {
3824
+ ${guard}
3825
+ const state = app.historyManager.getState();
3826
+ return { success: true, action: 'get_state', ...state };
3827
+ })();`.trim();
3828
+ default:
3829
+ return `(function() { return { error: 'Unknown history action: ${input.action}' }; })();`;
3830
+ }
3831
+ }
3832
+ // ===========================================================================
3833
+ // IMAGE PROCESSING
3834
+ // ===========================================================================
3835
+ generateImageFilter(input) {
3836
+ const guard = `if (!app.imageTools) return { error: 'ImageTools not available' };`;
3837
+ switch (input.action) {
3838
+ case 'apply':
3839
+ return `
3840
+ // Apply image filter
3841
+ (async function() {
3842
+ ${guard}
3843
+ try {
3844
+ const result = await app.imageTools.applyFilter(${JSON.stringify(input.itemId)}, ${JSON.stringify(input.filterName || '')}, ${JSON.stringify(input.params || {})});
3845
+ return { success: true, action: 'apply', itemId: ${JSON.stringify(input.itemId)}, filter: ${JSON.stringify(input.filterName || '')} };
3846
+ } catch (e) {
3847
+ return { error: 'Failed to apply filter: ' + e.message };
3848
+ }
3849
+ })();`.trim();
3850
+ case 'chain':
3851
+ return `
3852
+ // Apply filter chain
3853
+ (async function() {
3854
+ ${guard}
3855
+ try {
3856
+ const filters = ${JSON.stringify(input.filters || [])};
3857
+ const result = await app.imageTools.applyFilterChain(${JSON.stringify(input.itemId)}, filters);
3858
+ return { success: true, action: 'chain', itemId: ${JSON.stringify(input.itemId)}, filterCount: filters.length };
3859
+ } catch (e) {
3860
+ return { error: 'Failed to apply filter chain: ' + e.message };
3861
+ }
3862
+ })();`.trim();
3863
+ default:
3864
+ return `(function() { return { error: 'Unknown image_filter action: ${input.action}' }; })();`;
3865
+ }
3866
+ }
3867
+ generateLasso(input) {
3868
+ const guard = `if (!app.imageTools) return { error: 'ImageTools not available' };`;
3869
+ switch (input.action) {
3870
+ case 'activate':
3871
+ return `
3872
+ // Activate lasso selection
3873
+ (async function() {
3874
+ ${guard}
3875
+ try {
3876
+ await app.imageTools.activateLasso(${JSON.stringify(input.itemId || '')});
3877
+ return { success: true, action: 'activate', itemId: ${JSON.stringify(input.itemId || '')} };
3878
+ } catch (e) {
3879
+ return { error: 'Failed to activate lasso: ' + e.message };
3880
+ }
3881
+ })();`.trim();
3882
+ case 'apply':
3883
+ return `
3884
+ // Apply lasso selection
3885
+ (async function() {
3886
+ ${guard}
3887
+ try {
3888
+ const result = await app.imageTools.applyLasso();
3889
+ return { success: true, action: 'apply' };
3890
+ } catch (e) {
3891
+ return { error: 'Failed to apply lasso: ' + e.message };
3892
+ }
3893
+ })();`.trim();
3894
+ default:
3895
+ return `(function() { return { error: 'Unknown lasso action: ${input.action}' }; })();`;
3896
+ }
3897
+ }
3898
+ generateCutoutStyle(input) {
3899
+ const guard = `if (!app.imageTools) return { error: 'ImageTools not available' };`;
3900
+ switch (input.action) {
3901
+ case 'apply':
3902
+ return `
3903
+ // Apply cutout style
3904
+ (async function() {
3905
+ ${guard}
3906
+ try {
3907
+ const result = await app.imageTools.applyCutoutStyle(${JSON.stringify(input.itemId || '')}, ${JSON.stringify(input.preset || '')}, ${JSON.stringify(input.options || {})});
3908
+ return { success: true, action: 'apply', itemId: ${JSON.stringify(input.itemId || '')}, preset: ${JSON.stringify(input.preset || '')} };
3909
+ } catch (e) {
3910
+ return { error: 'Failed to apply cutout style: ' + e.message };
3911
+ }
3912
+ })();`.trim();
3913
+ case 'list':
3914
+ return `
3915
+ // List available cutout styles
3916
+ (function() {
3917
+ ${guard}
3918
+ const styles = app.imageTools.getCutoutStyles();
3919
+ return { success: true, action: 'list', styles };
3920
+ })();`.trim();
3921
+ default:
3922
+ return `(function() { return { error: 'Unknown cutout_style action: ${input.action}' }; })();`;
3923
+ }
3924
+ }
3925
+ // ===========================================================================
3926
+ // COMPOSITION & VIEW
3927
+ // ===========================================================================
3928
+ generatePrecomp(input) {
3929
+ switch (input.action) {
3930
+ case 'create': {
3931
+ const opts = {};
3932
+ if (input.name)
3933
+ opts.name = input.name;
3934
+ if (input.loop !== undefined)
3935
+ opts.loop = input.loop;
3936
+ if (input.duration !== undefined)
3937
+ opts.duration = input.duration;
3938
+ return `
3939
+ // Create precomp from items
3940
+ (function() {
3941
+ const itemIds = ${JSON.stringify(input.itemIds || [])};
3942
+ const opts = ${JSON.stringify(opts)};
3943
+ const precomp = app.createPrecomp(itemIds, opts);
3944
+ return { success: true, action: 'create', precompId: precomp?.id || precomp, name: ${JSON.stringify(input.name || '')} };
3945
+ })();`.trim();
3946
+ }
3947
+ case 'add':
3948
+ return `
3949
+ // Add item to precomp
3950
+ (function() {
3951
+ app.addToPrecomp(${JSON.stringify(input.precompId || '')}, ${JSON.stringify(input.itemId || '')});
3952
+ return { success: true, action: 'add', precompId: ${JSON.stringify(input.precompId || '')}, itemId: ${JSON.stringify(input.itemId || '')} };
3953
+ })();`.trim();
3954
+ case 'remove':
3955
+ return `
3956
+ // Remove item from precomp
3957
+ (function() {
3958
+ app.removeFromPrecomp(${JSON.stringify(input.precompId || '')}, ${JSON.stringify(input.itemId || '')});
3959
+ return { success: true, action: 'remove', precompId: ${JSON.stringify(input.precompId || '')}, itemId: ${JSON.stringify(input.itemId || '')} };
3960
+ })();`.trim();
3961
+ default:
3962
+ return `(function() { return { error: 'Unknown precomp action: ${input.action}' }; })();`;
3963
+ }
3964
+ }
3965
+ generateView(input) {
3966
+ switch (input.action) {
3967
+ case 'fit': {
3968
+ const mode = input.mode || 'content';
3969
+ const padding = input.padding ?? 20;
3970
+ return `
3971
+ // Fit view to ${mode}
3972
+ (function() {
3973
+ app.fitView('${mode}', ${padding});
3974
+ return { success: true, action: 'fit', mode: '${mode}', padding: ${padding} };
3975
+ })();`.trim();
3976
+ }
3977
+ case 'get_state':
3978
+ return `
3979
+ // Get current view state
3980
+ (function() {
3981
+ const state = app.getViewState();
3982
+ return { success: true, action: 'get_state', ...state };
3983
+ })();`.trim();
3984
+ default:
3985
+ return `(function() { return { error: 'Unknown view action: ${input.action}' }; })();`;
3986
+ }
3987
+ }
3988
+ generateBackground(input) {
3989
+ switch (input.action) {
3990
+ case 'set': {
3991
+ const mode = input.mode || 'color';
3992
+ if (mode === 'generator') {
3993
+ return `
3994
+ // Set background via generator
3995
+ (async function() {
3996
+ try {
3997
+ await app.executeGenerator(${JSON.stringify(input.generator || '')}, ${JSON.stringify(input.generatorParams || {})});
3998
+ return { success: true, action: 'set', mode: 'generator', generator: ${JSON.stringify(input.generator || '')} };
3999
+ } catch (e) {
4000
+ return { error: 'Failed to set generator background: ' + e.message };
4001
+ }
4002
+ })();`.trim();
4003
+ }
4004
+ if (mode === 'pattern') {
4005
+ return `
4006
+ // Set background pattern
4007
+ (function() {
4008
+ app.setBackgroundPattern(${JSON.stringify(input.pattern || '')});
4009
+ return { success: true, action: 'set', mode: 'pattern', pattern: ${JSON.stringify(input.pattern || '')} };
4010
+ })();`.trim();
4011
+ }
4012
+ // default: color
4013
+ return `
4014
+ // Set background color
4015
+ (function() {
4016
+ app.setBackgroundColor(${JSON.stringify(input.color || '#ffffff')});
4017
+ return { success: true, action: 'set', mode: 'color', color: ${JSON.stringify(input.color || '#ffffff')} };
4018
+ })();`.trim();
4019
+ }
4020
+ case 'clear':
4021
+ return `
4022
+ // Clear background
4023
+ (function() {
4024
+ app.clearBackground();
4025
+ return { success: true, action: 'clear' };
4026
+ })();`.trim();
4027
+ case 'get':
4028
+ return `
4029
+ // Get background info
4030
+ (function() {
4031
+ const bg = app.getBackground();
4032
+ return { success: true, action: 'get', ...bg };
4033
+ })();`.trim();
4034
+ default:
4035
+ return `(function() { return { error: 'Unknown background action: ${input.action}' }; })();`;
4036
+ }
4037
+ }
4038
+ // ===========================================================================
4039
+ // CANVAS QUERIES
4040
+ // ===========================================================================
4041
+ generateQuery(input) {
4042
+ switch (input.action) {
4043
+ case 'get_by_id':
4044
+ return `
4045
+ // Get item details by ID
4046
+ (function() {
4047
+ const entry = app.itemRegistry.get(${JSON.stringify(input.itemId || '')});
4048
+ if (!entry || !entry.item) return { error: 'Item not found: ${input.itemId}' };
4049
+ const item = entry.item;
4050
+ return {
4051
+ success: true, action: 'get_by_id',
4052
+ itemId: ${JSON.stringify(input.itemId || '')},
4053
+ type: item.data?.itemType || item.className,
4054
+ position: { x: item.position.x, y: item.position.y },
4055
+ bounds: item.bounds ? { x: item.bounds.x, y: item.bounds.y, width: item.bounds.width, height: item.bounds.height } : null,
4056
+ visible: item.visible,
4057
+ opacity: item.opacity,
4058
+ rotation: item.rotation,
4059
+ selected: item.selected,
4060
+ };
4061
+ })();`.trim();
4062
+ case 'hit_test': {
4063
+ const tolerance = input.tolerance ?? 5;
4064
+ const all = input.all ?? false;
4065
+ return `
4066
+ // Hit test at point
4067
+ (function() {
4068
+ const point = new paper.Point(${input.x ?? 0}, ${input.y ?? 0});
4069
+ ${all
4070
+ ? `const results = app.hitTestAll(point, { tolerance: ${tolerance} });
4071
+ const hits = results.map(r => ({
4072
+ itemId: r.item?.data?.itemId || r.item?.name || r.item?.id,
4073
+ type: r.item?.data?.itemType || r.item?.className,
4074
+ point: { x: r.point?.x, y: r.point?.y }
4075
+ }));
4076
+ return { success: true, action: 'hit_test', x: ${input.x ?? 0}, y: ${input.y ?? 0}, hits, count: hits.length };`
4077
+ : `const result = app.hitTest(point, { tolerance: ${tolerance} });
4078
+ if (!result) return { success: true, action: 'hit_test', x: ${input.x ?? 0}, y: ${input.y ?? 0}, hit: null };
4079
+ return {
4080
+ success: true, action: 'hit_test',
4081
+ x: ${input.x ?? 0}, y: ${input.y ?? 0},
4082
+ hit: { itemId: result.item?.data?.itemId || result.item?.name || result.item?.id, type: result.item?.data?.itemType || result.item?.className }
4083
+ };`}
4084
+ })();`.trim();
4085
+ }
4086
+ case 'is_empty':
4087
+ return `
4088
+ // Check if canvas is empty
4089
+ (function() {
4090
+ const items = app.itemRegistry.getAll();
4091
+ return { success: true, action: 'is_empty', empty: items.length === 0, count: items.length };
4092
+ })();`.trim();
4093
+ default:
4094
+ return `(function() { return { error: 'Unknown query action: ${input.action}' }; })();`;
4095
+ }
4096
+ }
3468
4097
  }
3469
4098
  // Export singleton instance
3470
4099
  export const codeGenerator = new PinePaperCodeGenerator();