import {LitElement, html} from "lit" import {property} from "lit/decorators.js" import styles from "./styles.js" import {transitions} from "./constants.js" import keyframesSvg from "../../icons/keyframes.svg.js" import addSvg from "../../icons/gravity-ui/add.svg.js" import bellSvg from "../../icons/gravity-ui/bell.svg.js" import codeSvg from "../../icons/remix-icon/code.svg.js" import syncSvg from "../../icons/remix-icon/sync.svg.js" import {removeLoadingPageIndicator} from "../../main.js" import lockSvg from "../../icons/gravity-ui/lock.svg.js" import githubSvg from "../../icons/remix-icon/github.svg.js" import peopleSvg from "../../icons/gravity-ui/people.svg.js" import shieldSvg from "../../icons/gravity-ui/shield.svg.js" import discordSvg from "../../icons/remix-icon/discord.svg.js" import speechToTextSvg from "../../icons/speech-to-text.svg.js" import computerSvg from "../../icons/remix-icon/computer.svg.js" import arrowRightSvg from "../../icons/gravity-ui/arrow-right.svg.js" import rocketSvg from "../../icons/material-design-icons/rocket.svg.js" import externalLinkSvg from "../../icons/gravity-ui/external-link.svg.js" export class LandingPage extends LitElement { static styles = styles @property({type: Boolean}) menuOpened = false @property({type: String}) currentTransition = transitions[0] @property({type: Boolean}) transitionsDropdownOpen = false transitionsVideo: null | HTMLVideoElement = null interval = 0 // Toggle transitions dropdown toggleTransitionsDropdown = (e: MouseEvent) => { e.stopPropagation() this.transitionsDropdownOpen = !this.transitionsDropdownOpen this.requestUpdate() if (this.transitionsDropdownOpen) { setTimeout(() => { window.addEventListener('click', this.closeTransitionsDropdown) }, 0) } } // Close transitions dropdown closeTransitionsDropdown = (e: MouseEvent) => { const dropdown = this.shadowRoot?.querySelector('.transitions-dropdown') const moreButton = this.shadowRoot?.querySelector('.more-transitions') if (dropdown && moreButton && !dropdown.contains(e.target as Node) && !moreButton.contains(e.target as Node)) { this.transitionsDropdownOpen = false this.requestUpdate() window.removeEventListener('click', this.closeTransitionsDropdown) } } menuClick = (e: MouseEvent) => { const hamburger = e.composedPath().find(e => (e as HTMLElement).className === "menu-icon") const navmenu = e.composedPath().find(e => (e as HTMLElement).className === "menu") if(hamburger) return if(!navmenu) { this.menuOpened = false this.requestUpdate() } } setCurrentTransition(e: Event) { const target = e.currentTarget as HTMLElement const index = target.getAttribute("data-index") if(index) { const transitionDuration = 3.492 this.transitionsVideo!.currentTime = +index * transitionDuration this.currentTransition = transitions[Math.floor(+index)] this.requestUpdate() } } connectedCallback() { super.connectedCallback() window.addEventListener("click", this.menuClick) removeLoadingPageIndicator() } disconnectedCallback() { clearInterval(this.interval) super.disconnectedCallback() window.removeEventListener("click", this.menuClick) window.removeEventListener('click', this.closeTransitionsDropdown) } firstUpdated() { const transitionDuration = 3.492 const video = this.shadowRoot?.querySelector(".transitions-video") as HTMLVideoElement this.transitionsVideo = video this.interval = setInterval(() => { const index = Math.floor(video.currentTime / transitionDuration) this.currentTransition = transitions[index] this.requestUpdate() }, 100) const path = this.getCurrentPath() this.scrollIntoElementView(path) } getCurrentPath() { return window.location.hash.slice(1) || "/" } scrollIntoElementView(id: string) { try { const element = this.shadowRoot?.querySelector(`#${id}`) element?.scrollIntoView({behavior: "smooth"}) } catch(e) {} } render() {return html`

video editor on the web

Powerful video editor
right in your browser

Open-source, privacy-focused, runs everywhere.
All your data stays on your device.

Capabilities

All the basic stuff, you can add audio/image/text/video and trim or split it, but there's more!

Trim

Split

Text

Images

Audio

Animations

7 animations to play with
but there's more to come!

Filters

As much as 30+ filters!
you can mix and match them too.

Resizable Panels

Adjustable panels
customize workspace the way you want

Local Fonts

Auto-loading fonts from
your device for seamless typography.

Export your video up to 4k!

  • No credit card required! 🤯
  • Unparalleled speed
  • Choose desired
    bitrate & aspect ratio
  • Try it out! Open editor

Edit Together in Real-Time

Create amazing videos as a team with Omniclip's powerful collaboration features. Multiple editors can work on the same project simultaneously, seeing changes instantly.

  • ${peopleSvg}

    Multi-User Editing

    Invite teammates to edit your project in real-time

  • ${syncSvg}

    Instant Sync

    See changes immediately across all connected devices

Try Collaboration Now

Community-Driven Transitions

Powered by GL Transitions, a collection of GLSL transitions created by developers worldwide.

${codeSvg}

Open Source Transitions

Access to 60+ high-quality transitions created and maintained by the community

${rocketSvg}

GPU-Accelerated

Blazing fast performance with WebGL for smooth transitions even in 4K

Transition: ${this.currentTransition} 1/30

Open source

Yep, it's open source! See how it's built, tweak it, or pitch in, all with the freedom of an MIT license.

Free

Totally free, no strings attached. Use it, create with it, and enjoy no hidden costs or sneaky subscriptions.

🌟 🌟

Privacy

Your data stays yours, everything happens locally on your device.

${lockSvg}

Security

No uploads, no risks. Everything runs safely within your browser.

${shieldSvg}

Client side

Powered by WebCodecs for native-speed rendering and export.

${computerSvg}

Coming Soon New Features

We're constantly improving Omniclip with powerful new features to make your video editing experience even better.

${keyframesSvg}

Keyframes

Take precise control over your animations with powerful keyframe editor. Create smooth transitions, complex movements, and professional effects with ease.

  • Multi-property animation
  • Customizable easing functions
  • Visual keyframe timeline
  • Copy and paste keyframes
${speechToTextSvg}

Speech to Text

Automatically generate accurate captions for your videos with built-in speech recognition. Save hours of manual transcription work and make your content more accessible.

  • Automatic caption generation
  • Multiple language support
  • Editable transcript
  • Caption styling options

For developers Coming Soon

Take full control of Omniclip projects through code, automation, or CI/CD pipelines.

Omni Tools API

  • Modular library for code-driven video editing
  • Powerful core with CLI, timeline format, and templates integration

// Create a video timeline programmatically
const watermark = subtitle("omniclip")
const xfade = crossfade(500)

const timeline = sequence(
  video("opening-credits.mp4"),
  xfade,
  stack(
    video("skateboarding.mp4"),
    watermark
  ),
  xfade,
  stack(
    video("biking.mp4"),
    watermark
  )
)
								

CLI Automation

  • Render video projects via CLI (headless mode)
  • Automate batch video exports, pipelines, or dev workflows

$ omnitool render project.json --output video.mp4
$ omnitool batch-render ./projects/* --output-dir ./exports
									

Omni Timeline Format

  • Fully documented JSON timeline schema
  • AI/automation compatible for custom agents or external tools

// e.g. something like this 🤔
{
  "root": "root-1",
  "items": [
    ["root-1", ["sequence", { "children": ["video-1", "stack-1"] }]],
    ["video-1", ["video", { ... }]],
    ["stack-1", ["stack", { "children": ["text-1", "audio-1"] }]],
    ["text-1", ["text", { ... }]],
    ["audio-1", ["audio", { ... }]]
  ]
}
									

Reusable Templates

  • Build timeline templates to speed up repetitive workflows
  • Share and import templates across projects and teams
` }}