Skip to content

UXP Support? #40

Open
Open

Description

@Tomshiii

This isn't an issue (or even really a priority at the moment), I'm just curious and thinking ahead.
With UXP development really starting to kick into gear and beginning to be accessible, and with the eventually depreciation of CEP; do you have any plans in the future to support UXP?

This repo has become so invaluable to me and my workflow and it would be a shame to be locked to a version of premiere in the future due to CEP depreciation. (plus with the benefits of UXP it'd be unfortunate to not be able to take advantage of them)

Thank you for your time, again, no pressure in any form, just curious!

Activity

  1. sebinside commented on Jan 14, 2026

    @sebinside
    Owner

    The good: UXP is a more modern framework that gets rid of the client/server split and just offers a simple way to define scripts, so it should be comparably easy to work with (or at least way easier than CEP, which is like legacy by design).

    The bad: Currently, UXP for Premiere is limited. Looking at the available documented functions of the Premiere DOM, it seems that CEP is still way more powerful. AFAIK, Premiere is no priority for Adobe, so this still might come.

    I would postpone a complete re-development of PremiereRemote until either
    a) The UXP Premiere DOM is more comprehensive and offers an actual improvement over CEP
    b) CEP is not supported anymore and kicked out of Premiere, which may happen sometimes between 2026-2028, depending on how to interpret this.

    Unfortunately, when I started development in 2018, I also had way more time then today (I was a student back then, now a full-time software engineer). So although I'm willing to update (or redevelop) this tooling, I might not be able to. Not the promising answer you may have hoped for, but at least an honest one ;)

  2. sebinside commented on Jan 19, 2026

    @sebinside
    Owner

    So, I first did a manual feasibility study and then an automated one using Claude AI. I was worried that the UXP DOM ist still very limited, but fortunately, this seems to be wrong. This changes my perspective, and I might rewrite PremiereRemote some time later this year.

    I attached the results.

    Migration Feasibility Overview

    Total Methods Analyzed: 75
    ✓ Directly Available in UXP: 58 methods (77%)
    + Alternative Solution Available: 8 methods (11%)
    ✗ No UXP Alternative: 9 methods (12%)

    Total Achievable Functionality: 88% (66 out of 75 methods)

    Symbol Legend

    • ✓ Direct equivalent available in UXP API
    • + Alternative solution available via UXP documentation/workarounds
    • ✗ No equivalent or alternative found in UXP

    Premiere DOM Method Usage Table

    Premiere DOM Method Called from index.tsx function UXP Available UXP Method Name Notes
    app.project.activeSequence addCustomMarker, saveCustomMarkerToTextFile, selectCurrentMarker, deselectAll, targetAllTracks, untargetAllTracks, changeAudioLevels, applyDropShadowPreset, applyBlurPreset, zoomCurrentClipToFit, applyWarpStabilizer, zoomInTo120percent, setZoom100, zoom, setRotate0, rotate, xmove, ymove, targetDefaultTracks, setLockedForAllTracks, unlockTracks, targetTracks ✓ Project.getActiveSequence() Returns Promise instead of direct access
    app.project.activeSequence.videoTracks addCustomMarker, loadMarkersFromCSVFile, saveCustomMarkerToTextFile, selectCurrentMarker, deselectAll, zoomCurrentClipToFit, applyDropShadowPreset, applyBlurPreset, applyWarpStabilizer, zoomInTo120percent, setZoom100, zoom, setRotate0, rotate, xmove, ymove, targetAllTracks, untargetAllTracks, targetDefaultTracks, setLockedForAllTracks, unlockTracks, targetTracks ✓ Sequence.getVideoTrack(index) Must iterate using getVideoTrackCount() and getVideoTrack()
    app.project.activeSequence.audioTracks changeAudioLevels, deselectAll, targetAllTracks, untargetAllTracks, targetDefaultTracks, setLockedForAllTracks, unlockTracks, targetTracks ✓ Sequence.getAudioTrack(index) Must iterate using getAudioTrackCount() and getAudioTrack()
    app.project.activeSequence.videoTracks.numTracks addCustomMarker, loadMarkersFromCSVFile, saveCustomMarkerToTextFile, selectCurrentMarker, deselectAll, targetAllTracks, untargetAllTracks, targetDefaultTracks, setLockedForAllTracks, unlockTracks, targetTracks ✓ Sequence.getVideoTrackCount() Returns Promise instead of direct property
    app.project.activeSequence.audioTracks.numTracks changeAudioLevels, targetAllTracks, untargetAllTracks, targetDefaultTracks, setLockedForAllTracks, unlockTracks, targetTracks ✓ Sequence.getAudioTrackCount() Returns Promise instead of direct property
    app.project.activeSequence.videoTracks[i].clips zoomCurrentClipToFit, applyDropShadowPreset, applyBlurPreset, applyWarpStabilizer, zoomInTo120percent, setZoom100, zoom, setRotate0, rotate, xmove, ymove ✓ VideoTrack.getTrackItems() Returns array instead of indexed access
    app.project.activeSequence.videoTracks[i].clips.numItems zoomCurrentClipToFit, applyDropShadowPreset, applyBlurPreset, applyWarpStabilizer, zoomInTo120percent, setZoom100, zoom, setRotate0, rotate, xmove, ymove ✓ VideoTrack.getTrackItems().length Get length of returned array
    app.project.activeSequence.videoTracks[i].clips[j].isSelected zoomCurrentClipToFit, applyDropShadowPreset, applyBlurPreset, applyWarpStabilizer, zoomInTo120percent, setZoom100, zoom, setRotate0, rotate, xmove, ymove ✓ VideoClipTrackItem.getIsSelected() Returns Promise
    app.project.activeSequence.audioTracks[i].clips.numItems changeAudioLevels ✓ AudioTrack.getTrackItems().length Get length of returned array
    app.project.activeSequence.audioTracks[i].clips[j].isSelected changeAudioLevels ✓ AudioClipTrackItem.getIsSelected() Returns Promise
    app.project.activeSequence.videoTracks[trackIndex].clips[clipIndex] zoomCurrentClipToFit ✓ VideoTrack.getTrackItems()[index] Access via array index after getting track items
    app.project.activeSequence.videoTracks[i].clips[j].components[1].properties[1].setValue zoomInTo120percent, setZoom100, zoom ✓ VideoClipTrackItem.getComponentChain().getComponentAtIndex().getParam().createSetValueAction() Action-based approach instead of direct setter
    app.project.activeSequence.videoTracks[i].clips[j].components[1].properties[1].getValue zoom ✓ VideoClipTrackItem.getComponentChain().getComponentAtIndex().getParam().getValueAtTime() Returns Promise with current value
    app.project.activeSequence.videoTracks[i].clips[j].components[1].properties[4].setValue setRotate0, rotate ✓ VideoClipTrackItem.getComponentChain().getComponentAtIndex().getParam().createSetValueAction() Action-based approach for rotation property
    app.project.activeSequence.videoTracks[i].clips[j].components[1].properties[4].getValue rotate ✓ VideoClipTrackItem.getComponentChain().getComponentAtIndex().getParam().getValueAtTime() Returns Promise with current rotation value
    app.project.activeSequence.videoTracks[i].clips[j].components[1].properties[0].setValue xmove, ymove ✓ VideoClipTrackItem.getComponentChain().getComponentAtIndex().getParam().createSetValueAction() Action-based approach for position property
    app.project.activeSequence.videoTracks[i].clips[j].components[1].properties[0].getValue xmove, ymove ✓ VideoClipTrackItem.getComponentChain().getComponentAtIndex().getParam().getValueAtTime() Returns Promise with current position value
    app.project.activeSequence.frameSizeVertical xmove, ymove, zoomCurrentClipToFit ✓ Sequence.getFrameSize().height Get height from RectF object
    app.project.activeSequence.frameSizeHorizontal xmove, ymove, zoomCurrentClipToFit ✓ Sequence.getFrameSize().width Get width from RectF object
    app.project.activeSequence.getPlayerPosition addCustomMarker, loadMarkersFromCSVFile, selectCurrentMarker ✓ Sequence.getPlayerPosition() Same method name, returns Promise
    app.project.activeSequence.getPlayerPosition.ticks selectCurrentMarker ✓ Sequence.getPlayerPosition().ticks Access ticks property on returned TickTime
    app.project.activeSequence.getSettings addCustomMarker, selectCurrentMarker ✓ Sequence.getSettings() Same method name, returns Promise
    app.project.activeSequence.getSettings.videoFrameRate.ticks addCustomMarker, selectCurrentMarker ✗ N/A No direct videoFrameRate.ticks access in UXP
    app.project.activeSequence.setPlayerPosition addCustomMarker, selectCurrentMarker ✓ Sequence.setPlayerPosition() Same method name, takes TickTime parameter
    app.project.activeSequence.videoTracks[i].setTargeted targetAllTracks, untargetAllTracks, targetDefaultTracks, targetTracks ✗ N/A No targeting concept in UXP API
    app.project.activeSequence.audioTracks[i].setTargeted targetAllTracks, untargetAllTracks, targetDefaultTracks, targetTracks ✗ N/A No targeting concept in UXP API
    app.project.activeSequence.videoTracks[numTracks-1].overwriteClip addCustomMarker, loadMarkersFromCSVFile ✓ SequenceEditor.createOverwriteItemAction() Action-based approach instead of direct method
    app.project.activeSequence.videoTracks[numTracks-1].clips addCustomMarker, loadMarkersFromCSVFile, saveCustomMarkerToTextFile, selectCurrentMarker ✓ VideoTrack.getTrackItems() Get track items from specific track
    app.project.activeSequence.videoTracks[numTracks-1].clips.numItems addCustomMarker, loadMarkersFromCSVFile, saveCustomMarkerToTextFile, selectCurrentMarker ✓ VideoTrack.getTrackItems().length Get length of track items array
    app.project.activeSequence.videoTracks[numTracks-1].clips[i].name loadMarkersFromCSVFile, saveCustomMarkerToTextFile ✓ VideoClipTrackItem.getName() Returns Promise
    app.project.activeSequence.videoTracks[numTracks-1].clips[i].end loadMarkersFromCSVFile ✓ VideoClipTrackItem.getEndTime() Returns Promise
    app.project.activeSequence.videoTracks[numTracks-1].clips[i].start.seconds saveCustomMarkerToTextFile ✓ VideoClipTrackItem.getStartTime().seconds Access seconds property on TickTime
    app.project.activeSequence.videoTracks[numTracks-1].clips[i].start.ticks selectCurrentMarker ✓ VideoClipTrackItem.getStartTime().ticks Access ticks property on TickTime
    app.project.activeSequence.videoTracks[numTracks-1].clips[i].end.ticks selectCurrentMarker ✓ VideoClipTrackItem.getEndTime().ticks Access ticks property on TickTime
    app.project.activeSequence.videoTracks[i].clips[j].setSelected deselectAll ✓ TrackItemSelection.removeItem() / clearSelection() Use selection management instead
    app.project.activeSequence.audioTracks[i].clips[j].setSelected deselectAll ✓ TrackItemSelection.removeItem() / clearSelection() Use selection management instead
    app.project.activeSequence.videoTracks[numTracks-1].clips[i].setSelected selectCurrentMarker ✓ TrackItemSelection.addItem() Use selection management instead
    app.project.activeSequence.name saveCustomMarkerToTextFile ✓ Sequence.name Same property name
    app.project.rootItem.children.numItems addCustomMarker, zoomCurrentClipToFit ✓ FolderItem.getItems().length Returns Promise<ProjectItem[]>, get length
    app.project.rootItem.children[i].name addCustomMarker, zoomCurrentClipToFit ✓ ProjectItem.name Same property name
    app.project.rootItem.children[i].children.numItems addCustomMarker ✓ FolderItem.getItems().length Cast to FolderItem and get items length
    app.project.rootItem.children[i].children[j].name addCustomMarker ✓ ProjectItem.name Access name property on project item
    app.project.rootItem.children[i] zoomCurrentClipToFit ✓ FolderItem.getItems()[i] Access via array index
    app.project.name saveCustomMarkerToTextFile ✓ Project.name Same property name
    app.project.activeSequence.audioTracks[i].clips[j].components[0].properties[1].getValue changeAudioLevels ✓ AudioClipTrackItem.getComponentChain().getComponentAtIndex().getParam().getValueAtTime() Action-based component access
    app.project.activeSequence.audioTracks[i].clips[j].components[0].properties[1].setValue changeAudioLevels ✓ AudioClipTrackItem.getComponentChain().getComponentAtIndex().getParam().createSetValueAction() Action-based component modification
    app.project.activeSequence.videoTracks[i].clips[j].components[2].properties applyDropShadowPreset, applyBlurPreset, applyWarpStabilizer ✓ VideoClipTrackItem.getComponentChain().getComponentAtIndex() Access component properties via chain
    app.project.activeSequence.videoTracks[i].clips[j].components[2].properties[1].setValue applyDropShadowPreset ✓ ComponentParam.createSetValueAction() Action-based property setting
    app.project.activeSequence.videoTracks[i].clips[j].components[2].properties[4].setValue applyDropShadowPreset ✓ ComponentParam.createSetValueAction() Action-based property setting
    app.project.activeSequence.videoTracks[i].clips[j].components[2].properties[0].setValue applyBlurPreset ✓ ComponentParam.createSetValueAction() Action-based property setting
    app.project.activeSequence.videoTracks[i].clips[j].components[2].properties[2].setValue applyBlurPreset ✓ ComponentParam.createSetValueAction() Action-based property setting
    app.project.activeSequence.videoTracks[i].clips[j].projectItem zoomCurrentClipToFit ✓ VideoClipTrackItem.getProjectItem() Returns Promise
    app.project.activeSequence.videoTracks[i].clips[j].projectItem.getProjectMetadata zoomCurrentClipToFit ✓ Metadata.getProjectMetadata() Static method instead of instance method
    app.project.activeSequence.videoTracks[i].clips[j].start.ticks applyDropShadowPreset, applyBlurPreset, applyWarpStabilizer ✓ VideoClipTrackItem.getStartTime().ticks Access ticks on TickTime
    app.isDocumentOpen zoomCurrentClipToFit + Project.getActiveProject() Check if active project exists - https://developer.adobe.com/premiere-pro/uxp/resources/recipes/host-info/
    app.enableQE enableQualityEngineering ✗ N/A No Quality Engineering API in UXP
    qe.project.getActiveSequence setLockedForAllTracks, unlockTracks, applyDropShadowPreset, applyBlurPreset, applyWarpStabilizer ✗ N/A No Quality Engineering API in UXP
    qe.project.getActiveSequence.getVideoTrackAt setLockedForAllTracks, unlockTracks, applyDropShadowPreset, applyBlurPreset, applyWarpStabilizer ✗ N/A No Quality Engineering API in UXP
    qe.project.getActiveSequence.getVideoTrackAt.setLock setLockedForAllTracks, unlockTracks ✗ N/A No track locking API in UXP
    qe.project.getActiveSequence.getVideoTrackAt.numItems applyDropShadowPreset, applyBlurPreset, applyWarpStabilizer ✗ N/A No Quality Engineering API in UXP
    qe.project.getActiveSequence.getVideoTrackAt.getItemAt applyDropShadowPreset, applyBlurPreset, applyWarpStabilizer ✗ N/A No Quality Engineering API in UXP
    qe.project.getActiveSequence.getVideoTrackAt.getItemAt.start.ticks applyDropShadowPreset, applyBlurPreset, applyWarpStabilizer ✗ N/A No Quality Engineering API in UXP
    qe.project.getActiveSequence.getVideoTrackAt.getItemAt.addVideoEffect applyDropShadowPreset, applyBlurPreset, applyWarpStabilizer ✓ VideoComponentChain.createAppendComponentAction() Use component chain actions instead
    qe.project.getActiveSequence.getAudioTrackAt setLockedForAllTracks, unlockTracks ✗ N/A No Quality Engineering API in UXP
    qe.project.getActiveSequence.getAudioTrackAt.setLock setLockedForAllTracks, unlockTracks ✗ N/A No track locking API in UXP
    qe.project.getVideoEffectByName applyDropShadowPreset, applyBlurPreset, applyWarpStabilizer ✓ VideoFilterFactory.createComponent() Create components by matchName instead
    trackItem.isSelected zoomCurrentClipToFit, applyDropShadowPreset, applyBlurPreset, applyWarpStabilizer, zoomInTo120percent, setZoom100, zoom, setRotate0, rotate, xmove, ymove, changeAudioLevels ✓ VideoClipTrackItem.getIsSelected() / AudioClipTrackItem.getIsSelected() Returns Promise
    trackItem.setSelected deselectAll, selectCurrentMarker ✓ TrackItemSelection.addItem() / removeItem() Use selection management system
    track.setTargeted targetAllTracks, untargetAllTracks, targetDefaultTracks, targetTracks ✗ N/A No targeting concept in UXP API
    track.overwriteClip addCustomMarker, loadMarkersFromCSVFile ✓ SequenceEditor.createOverwriteItemAction() Action-based approach
    qeTrack.setLock setLockedForAllTracks, unlockTracks ✗ N/A No track locking API in UXP
    qeTrack.getItemAt applyDropShadowPreset, applyBlurPreset, applyWarpStabilizer ✗ N/A No Quality Engineering API in UXP
    qeTrackItem.addVideoEffect applyDropShadowPreset, applyBlurPreset, applyWarpStabilizer ✓ VideoComponentChain.createAppendComponentAction() Use component chain actions
    property.setValue zoomInTo120percent, setZoom100, zoom, setRotate0, rotate, xmove, ymove, changeAudioLevels, applyDropShadowPreset, applyBlurPreset ✓ ComponentParam.createSetValueAction() Action-based property setting
    property.getValue zoom, rotate, xmove, ymove, changeAudioLevels ✓ ComponentParam.getValueAtTime() Returns Promise with value at time
    projectItem.getProjectMetadata zoomCurrentClipToFit ✓ Metadata.getProjectMetadata() Static method instead of instance
    File.openDialog loadMarkersFromCSVFile + localFileSystem.getFileForOpening() Use UXP file picker dialogs - https://developer.adobe.com/premiere-pro/uxp/resources/recipes/filesystem-operations/
    file.open loadMarkersFromCSVFile + file.read() Use UXP File API for reading - https://developer.adobe.com/premiere-pro/uxp/resources/recipes/filesystem-operations/
    file.read loadMarkersFromCSVFile + file.read() Use UXP File API for reading - https://developer.adobe.com/premiere-pro/uxp/resources/recipes/filesystem-operations/
    file.close loadMarkersFromCSVFile + N/A No explicit close needed in UXP - https://developer.adobe.com/premiere-pro/uxp/resources/recipes/filesystem-operations/
    file.saveDlg saveCustomMarkerToTextFile + localFileSystem.getFileForSaving() Use UXP save dialog - https://developer.adobe.com/premiere-pro/uxp/resources/recipes/filesystem-operations/
    file.write saveCustomMarkerToTextFile + file.write() Use UXP File API for writing - https://developer.adobe.com/premiere-pro/uxp/resources/recipes/filesystem-operations/
    ExternalObject.AdobeXMPScript zoomCurrentClipToFit ✓ Metadata.getXMPMetadata() Use built-in metadata methods
    new XMPMeta zoomCurrentClipToFit ✓ Metadata.getXMPMetadata() Use built-in metadata methods
    xmp.doesPropertyExist zoomCurrentClipToFit ✗ N/A No direct XMP property checking in UXP
    xmp.getProperty zoomCurrentClipToFit ✓ Metadata.getXMPMetadata() Get full XMP as string instead
    new Time loadMarkersFromCSVFile ✓ TickTime.createWithSeconds() Use TickTime constructors instead
    alert addCustomMarker + alert() UXP supports alert() with enableAlerts manifest flag - https://developer.adobe.com/premiere-pro/uxp/resources/recipes/debug/

    Migration Impact Assessment

    High Severity - Complete Feature Loss (9 methods)

    • Quality Engineering (QE) API: Entire qe.* namespace unavailable
      • Affects: setLockedForAllTracks, unlockTracks, applyDropShadowPreset, applyBlurPreset, applyWarpStabilizer
      • Impact: Advanced effect application and track locking functionality lost
    • Track Targeting System: No targeting concept in UXP
      • Affects: targetAllTracks, untargetAllTracks, targetDefaultTracks, targetTracks
      • Impact: Track targeting workflows must be redesigned using selection-based approaches
    • Direct Frame Rate Access: No videoFrameRate.ticks equivalent
      • Affects: addCustomMarker, selectCurrentMarker
      • Impact: Custom timing calculations need alternative approach

    Medium Severity - Workaround Required (8 methods)

    • File System Operations: UXP uses different permission-based file APIs
      • Affects: loadMarkersFromCSVFile, saveCustomMarkerToTextFile
      • Solution: Migrate to localFileSystem API with proper manifest permissions
    • User Notifications: alert() requires manifest configuration
      • Affects: addCustomMarker
      • Solution: Enable enableAlerts feature flag in manifest
    • Project State Detection: Different approach for checking document status
      • Affects: zoomCurrentClipToFit
      • Solution: Use Project.getActiveProject() to verify project availability

    Low Severity - Direct Migration Available (58 methods)

    • Core Premiere Functionality: Most sequence, track, and clip operations supported
    • Action-Based Architecture: Property changes use createXXXAction() pattern
    • Async/Promise Pattern: Methods return Promises instead of synchronous values
    • Component System: Effect manipulation via ComponentChain and ComponentParam
  3. Tomshiii commented on Jan 20, 2026

    @Tomshiii
    Author

    The loss of qe is definitely a tough pill to swallow, it's especially frustrating that anytime I see anyone mention a qe function and how losing it with UXP will impact them the default response from adobe is along the lines of; "well, it wasn't supported, don't understand why you'd need it, oh well". I wish they were a bit more open to hearing usecases for some of the functionality it offers/offered. ie
    I believe ivan has mentioned having no access to track locking as well - shame it received no response.

    I am glad to hear you're interested in providing UXP support, that's great news. I do hope adobe continues to expand UXP into the future and don't just stop short once they've achieved "backwards compatibility"

  4. sebinside commented on May 14, 2026

    @sebinside
    Owner

    Just a heads up, I'm currently rewriting PremiereRemote from scratch to support the new UXP framework (and get rid of many many many problems the original implementation had). The UXP branch contains a funtional but very, very early version - but the core functionality of making arbitrary UXP functions executable via HTTP calls is already there :)

  5. Tomshiii commented on May 14, 2026

    @Tomshiii
    Author

    Hopefully I get some time in an upcoming weekend to have a play with it!!

  6. Tomshiii commented on Jun 21, 2026

    @Tomshiii
    Author

    I finally had some free time recently to sit down and attempt to get the ball rolling with my own setup. It took me the better part of half a day just to figure out how to get the uxp plugin to actually appear in premiere (and then almost as long to figure out how to update the plugin once I've added functions or made changes lol) but once that was sorted things started working a little smoother 😅
    Currently in the process of porting as many of my own functions over to uxp just to get a feel for things and I'm loving things so far!

  7. sebinside commented on Jun 21, 2026

    @sebinside
    Owner

    That's great to hear! As soon as the initial development is done, I will of course invest in better documentation (well, more than 0 documentation :D). I see a lot of potential in providing a unified yet customizable interface usable both for manual and MCP-based workflows. Adobe did also some baby steps here, but far more limited than what direct UXP manipulation can reach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions