live
MODEL IDprunaai:p-video@2

P-Video-2

Pruna AI
by

P-Video-2 is Pruna AI's quality-focused successor to P-Video, creating clips from text, images, or audio-conditioned inputs through one model. It produces sharper close-ups and foreground subjects, stronger identity and input-image consistency, improved lip synchronization for natively generated speech, and clearer on-screen text while generating dialogue, music, and sound effects with the video. It supports optional first-and-last-frame guidance, draft iteration, durations up to 20 seconds, 720p or 1080p output, and 24 or 48 FPS.

P-Video-2

Pinning the first and last frame

How to give Pruna P-Video-2 both ends of a shot, how far apart the two stills can sit before the transition breaks, and the pairing trick that produces a seamless loop.

Introduction

A single first frame decides where a shot starts and leaves the ending to the model. Pinning both ends turns the request into a different kind of instruction: you are no longer describing motion and hoping, you are handing over a start state and an end state and asking for the path between them.

Both ends supplied, the reveal invented between them

The lid lifts smoothly straight up off the box, moves back and sets down behind it, the tissue paper folds open and the jar inside is revealed. Steady and unhurried, the camera holds still throughout. Audio: quiet studio room tone, the soft friction of a rigid lid lifting and tissue paper unfolding, no music, no voice.

Built from 2 references
  • First frame
  • Last frame

That is an unboxing shot where the product is guaranteed to be correct in the final frame, because the final frame is a still you approved. No amount of prompting a single first frame gets you that. This guide covers the request, how far apart the two ends can sit, how duration changes the pace of the transition, and the pairing that gives you a seamless loop.

The request

inputs.frameImages takes two items, one for each end. frame accepts the names "first" and "last", or the indices 0 and -1, and the two forms are interchangeable.

{
  "inputs": {
    "frameImages": [
      { "image": "https://…/closed.jpg", "frame": "first" },
      { "image": "https://…/open.jpg", "frame": "last" }
    ]
  }
}

Order in the array does not matter, because frame is what assigns the position. Naming both is the habit worth keeping: a bare image with no frame is read as the first frame, so a two-item array that forgets to label the second one is not the request you meant.

Try in Playground
import { createClient } from '@runware/sdk'

const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY })
await client.connect()

const [result] = await client.run({
  model: 'prunaai:p-video@2',
  positivePrompt: 'The lid lifts smoothly straight up off the box, moves back and sets down behind it, the tissue paper folds open and the jar inside is revealed. Steady and unhurried, the camera holds still throughout. Audio: quiet studio room tone, the soft friction of a rigid lid lifting and tissue paper unfolding, no music, no voice.',
  inputs: {
    frameImages: [
      {
        image: 'https://im.runware.ai/image/os/a14d18/ws/2/ii/2f9d4c81-7b35-4e60-9a18-5c2d8a7f1e93.jpg',
        frame: 'first'
      },
      {
        image: 'https://im.runware.ai/image/os/a14d18/ws/2/ii/6b3e8a15-4c92-4d07-8f61-9a2c7d5b3e48.jpg',
        frame: 'last'
      }
    ]
  },
  resolution: '720p',
  duration: 6,
  deliveryMethod: 'async'
})
import asyncio
import os

from runware import Runware


async def main():
    async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client:
        results = await client.run({
            "model": "prunaai:p-video@2",
            "positivePrompt": "The lid lifts smoothly straight up off the box, moves back and sets down behind it, the tissue paper folds open and the jar inside is revealed. Steady and unhurried, the camera holds still throughout. Audio: quiet studio room tone, the soft friction of a rigid lid lifting and tissue paper unfolding, no music, no voice.",
            "inputs": {
                "frameImages": [
                    {
                        "image": "https://im.runware.ai/image/os/a14d18/ws/2/ii/2f9d4c81-7b35-4e60-9a18-5c2d8a7f1e93.jpg",
                        "frame": "first"
                    },
                    {
                        "image": "https://im.runware.ai/image/os/a14d18/ws/2/ii/6b3e8a15-4c92-4d07-8f61-9a2c7d5b3e48.jpg",
                        "frame": "last"
                    }
                ]
            },
            "resolution": "720p",
            "duration": 6,
            "deliveryMethod": "async"
        })


asyncio.run(main())
curl https://api.runware.ai/v1 \
  -H "Authorization: Bearer $RUNWARE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '[
    {
      "taskType": "videoInference",
      "taskUUID": "a5c81e37-9d24-4b60-8f15-3e7a2c9d4b81",
      "model": "prunaai:p-video@2",
      "positivePrompt": "The lid lifts smoothly straight up off the box, moves back and sets down behind it, the tissue paper folds open and the jar inside is revealed. Steady and unhurried, the camera holds still throughout. Audio: quiet studio room tone, the soft friction of a rigid lid lifting and tissue paper unfolding, no music, no voice.",
      "inputs": {
        "frameImages": [
          {
            "image": "https://im.runware.ai/image/os/a14d18/ws/2/ii/2f9d4c81-7b35-4e60-9a18-5c2d8a7f1e93.jpg",
            "frame": "first"
          },
          {
            "image": "https://im.runware.ai/image/os/a14d18/ws/2/ii/6b3e8a15-4c92-4d07-8f61-9a2c7d5b3e48.jpg",
            "frame": "last"
          }
        ]
      },
      "resolution": "720p",
      "duration": 6,
      "deliveryMethod": "async"
    }
  ]'
runware run prunaai:p-video@2 \
  positivePrompt="The lid lifts smoothly straight up off the box, moves back and sets down behind it, the tissue paper folds open and the jar inside is revealed. Steady and unhurried, the camera holds still throughout. Audio: quiet studio room tone, the soft friction of a rigid lid lifting and tissue paper unfolding, no music, no voice." \
  inputs.frameImages.0.image=https://im.runware.ai/image/os/a14d18/ws/2/ii/2f9d4c81-7b35-4e60-9a18-5c2d8a7f1e93.jpg \
  inputs.frameImages.0.frame=first \
  inputs.frameImages.1.image=https://im.runware.ai/image/os/a14d18/ws/2/ii/6b3e8a15-4c92-4d07-8f61-9a2c7d5b3e48.jpg \
  inputs.frameImages.1.frame=last \
  resolution=720p \
  duration=6 \
  deliveryMethod=async
{
  "taskType": "videoInference",
  "taskUUID": "a5c81e37-9d24-4b60-8f15-3e7a2c9d4b81",
  "model": "prunaai:p-video@2",
  "positivePrompt": "The lid lifts smoothly straight up off the box, moves back and sets down behind it, the tissue paper folds open and the jar inside is revealed. Steady and unhurried, the camera holds still throughout. Audio: quiet studio room tone, the soft friction of a rigid lid lifting and tissue paper unfolding, no music, no voice.",
  "inputs": {
    "frameImages": [
      {
        "image": "https://im.runware.ai/image/os/a14d18/ws/2/ii/2f9d4c81-7b35-4e60-9a18-5c2d8a7f1e93.jpg",
        "frame": "first"
      },
      {
        "image": "https://im.runware.ai/image/os/a14d18/ws/2/ii/6b3e8a15-4c92-4d07-8f61-9a2c7d5b3e48.jpg",
        "frame": "last"
      }
    ]
  },
  "resolution": "720p",
  "duration": 6,
  "deliveryMethod": "async"
}
Response
[
  {
    "taskType": "videoInference",
    "taskUUID": "a5c81e37-9d24-4b60-8f15-3e7a2c9d4b81",
    "videoUUID": "9e4a7c25-3f18-4b60-8d73-1c5a9d2f7b84",
    "videoURL": "https://vm.runware.ai/video/os/a14d18/ws/2/vi/9e4a7c25-3f18-4b60-8d73-1c5a9d2f7b84.mp4"
  }
]

Everything that applies to a single first frame applies here too. width and height are still rejected, the aspect still comes from the stills, and resolution still picks the tier. Animating a still covers that rule and the source-quality requirements, both of which now apply twice over.

The pair has to match

Two stills that disagree about anything other than the thing you want to change will not interpolate. The pair below is a deliberate bad one, changing three things at once so you can see what that looks like:

That pair asks for a camera move, a lens change and a lighting change in six seconds. There is no single continuous path that does all three, so the model stops trying to find one: it holds the first frame, then cross-fades into the second, with a brief double exposure in the middle where both rooms are visible at once.

That fade is worth recognizing, because it is the model telling you something. A dissolve means your pair was unreachable. When two frames are connected by something physical, you get movement instead, the way the lid lifts off the box above. When they are not, you get a slideshow transition. Watch the middle third of any first-and-last clip: ghosting there means the ends were too far apart, whatever the prompt asked for.

The rule that comes out of it: change one thing between the two frames. The light, or the position of an object, or the camera, not several. When a shot genuinely needs a move and a light change, split it into two clips and cut.

Everything else about the pair should be identical: the aspect ratio, the focal length, the position of the camera, the palette, and anything in frame you are not deliberately changing. The most reliable way to get that is to generate the second still from the first one in your image model rather than writing it fresh.

How far apart the two ends can sit

The interesting question is not whether two stills work, it is how much distance the interpolation can cover. Three pairs from one anchor still, all on the same seed and duration:

The near pair is the sweet spot. Nothing physical moves, one property of the scene changes, and the model only has to interpolate light, which it does convincingly enough to sell as a time-lapse.

The mid pair still works and asks more: the window content changes, two lamps switch on, and the whole light direction inverts. Watch the lamps rather than the window, because a light source coming up is where the invention shows.

The far pair is not a transition, it is a dissolve. Two unrelated scenes produce a morph, with the sofa melting into shopfronts, because there is no physical path between a hotel room and a street. That is a real effect if you want it, and it is nothing like a cut. When you need the suite and then the street, generate two clips and cut them.

The distance that matters is physical continuity, not visual similarity. Two stills that look quite different but share a cause, a lamp switching on, a lid coming off, a garment being unfolded, interpolate better than two stills that look alike but have no motion connecting them.

Duration sets the pace

With both ends fixed, duration stops being "how long a clip do I want" and becomes how fast the transition happens, because the model has to arrive at the last frame exactly on time. The same pair at three lengths:

Three seconds reads as a transition effect. Twelve reads as a time-lapse. Neither is wrong, and the same two stills give you both without regenerating anything, which makes duration the cheapest creative control in this mode.

There is a practical limit at each end. Too short and a physical action gets compressed into something that snaps rather than moves. Too long and the model has to fill seconds with invention it was not given any instruction for, which is where drifting appears in the middle of an otherwise clean clip. For a physical action, match the duration to how long the action would actually take. A rigid box lid comes off in about a second, so a six-second reveal wants the prompt to say the movement is unhurried, exactly as the hero prompt does.

duration is rejected when inputs.audio is present, because imported audio sets the length instead. Pinning both frames and supplying a track means the transition is paced by the audio, not by you. Audio-driven generation covers that combination.

A seamless loop from one still

Here is the trick worth knowing. Pass the same image as both the first and the last frame, and the clip is guaranteed to end where it began.

{
  "inputs": {
    "frameImages": [
      { "image": "https://…/mug.jpg", "frame": "first" },
      { "image": "https://…/mug.jpg", "frame": "last" }
    ]
  }
}

That is a perfect loop point, which is normally the hardest thing to get out of a generative video model. The prompt's job changes: it has to describe motion that returns to rest, since anything that ends somewhere else has to be walked back before the final frame.

Ends on the frame it started on

Steam rises gently from the surface of the coffee and drifts, and the surface of the liquid ripples very slightly, returning to stillness by the end. The camera holds perfectly still and the mug does not move. Audio: quiet room tone, no music, no voice.

Built from 1 reference
  • First and last frame

Loops earn their keep in the places video autoplays and repeats: a listing page, a hero banner, a background panel in an app. Because the seam is exact, the file can be played on repeat with no cut visible, and a five-second clip covers a slot that would otherwise need a much longer render.

The motions that suit this are the ones that naturally cycle or settle. Steam, a curtain in a draught, a plant moving in air, a fabric settling, a light flickering. Anything with a direction to it will fight the last frame, so a rotation, a walk or a hand entering shot are the wrong instructions here.

Pair it with settings.audio: false and you have exactly what a muted autoplay loop needs, since a generated track will not loop cleanly even when the picture does.

Tips

  1. Label both frames. An item without frame is treated as the first frame, so a two-item array with one label is a request for two first frames.

  2. Change one thing between the ends. Light, or an object's position, or the camera. Two of the three at once produces a lurch, not a transition.

  3. Generate the last still from the first. Editing the first frame in your image model keeps the framing, lens and palette identical, which is most of what makes a pair work.

  4. Ask for a cause, not a resemblance. Two frames connected by something physically happening interpolate well. Two frames that merely look alike do not.

  5. Use duration as the pace control. One pair at 3, 6 and 12 seconds gives you a transition, a beat and a time-lapse. Match it to how long the real action would take.

  6. Pass the same still twice for a seamless loop, and write motion that returns to rest. Steam, draught and settling fabric loop. Rotations and walks do not.

  7. Turn the audio off on loops. The picture loops exactly and the generated track will not, so a muted loop is the only clean version.

  8. Two unrelated stills are a morph, not a cut. If you want a cut, render two clips and cut them in your edit.