Console

Effing up in the cloud?Leave it to us. We made it.

Run your Effing functions and video renders in the cloud, hosted by the OGs. Access controls, analytics, diagnostics — it’s all built in and ready to go.

cloud.effing.dev/console
ffs
Overview
Filter by tags
Renders
12,847
Errors
23
Avg render time
32s
P95 render time
57s
Renders and errors
Render time
Average video duration

What do you get?Big deploy energy.

Just effing-cloud deploy and you’re up in the cloud, with all of the usual perks that brings. And you get to:

TEMPLATE

Template like crazy

Write an fn module once in TypeScript, then drop whatever props you want into the URL. Ten variants or ten thousand, it doesn't matter. One image or video per row of a huge product catalog? No biggie.

TRACK

Track with tags

Tag every render and function run with whatever matters to you — customer, campaign, experiment, locale. Everything in the console can then be sliced by tag, so you can see exactly what's going on for each slice.

SCALE

Scale to zero

We scale down as well as up. When nothing is rendering, you're not paying. It's completely possible to burst out a campaign's worth of images and videos all at once, then back to zero until the next push.

How does it work?npx and chill.

From an empty project to a rendered video you can keep tabs on, in six steps. No infrastructure, no Docker, no YAML.

  1. 1

    Install and log in

    It’s an npm package. Drop it into your project, then authenticate by running npx effing-cloud login. It’ll open a browser tab where you can authorize the device.

    terminal
    $ npm i -D effing-cloud
    $ npx effing-cloud login
    logged in as [email protected]
  2. 2

    Write an effie module

    An effie is a TypeScript module that returns a video composition. Same shape as images and annies — a Zod props schema, sample preview props, and an async runner. Read the Effing tutorial for the full anatomy.

    app/effies/poster.fn.tsx
    import { z } from "zod";
    import { effieData, effieSegment } from "@effing/effie";
    import type { RunnerArgs, EffieRunnerReturn } from "@effing/fn";
    
    export const propsSchema = z.object({
      imageUrl: z.string().url(),
      duration: z.number().default(5),
    });
    
    type Props = z.infer<typeof propsSchema>;
    
    export const previewProps: Props = {
      imageUrl: "https://static.effing.dev/picsum/1080/1920/sky.jpg",
      duration: 5,
    };
    
    export async function runner({
      props: { imageUrl, duration },
      bounds: { width, height },
    }: RunnerArgs<Props>): EffieRunnerReturn {
      return effieData({
        width,
        height,
        fps: 30,
        segments: [
          effieSegment({
            duration,
            layers: [{ type: "image", source: imageUrl }],
          }),
        ],
      });
    }
  3. 3

    Point at it, deploy

    The config file lists your module globs. effing-cloud deploy bundles them and ships them. Projects scaffolded with npm create @effing come with both pre-wired — an effing.config.ts and a cloud:deploy npm script.

    effing.config.ts
    import { defineConfig } from "@effing/dev";
    
    export default defineConfig({
      project: "posters",
      effies: "app/effies/*.fn.tsx",
    });
    terminal
    $ npx effing-cloud deploy
    posters v3 — 1 effie module
  4. 4

    Mint signed URLs

    Pass your props to the official JS/TS or Python SDK to get a tamper-proof signed URL. For images, use the URL directly. Effies need to be rendered first to produce a video — that’s the final step.

    server.ts
    import { EffingCloudClient } from "effing-cloud-sdk";
    
    // secret is printed by `effing-cloud url-secret`
    const client = new EffingCloudClient({
      tenant: "acme",
      project: "posters",
      secret: process.env.EFFING_URL_SECRET!,
    });
    
    const posterUrl = await client.mintSignedUrl({
      kind: "effie",
      id: "poster",
      props: { imageUrl: "https://cdn.example.com/sky.jpg", duration: 5 },
      bounds: { width: 1080, height: 1920 },
    });
    
    // https://fn.effing.dev/acme/posters/effie/<segment>
  5. 5

    Render videos

    POST your signed effie URL to ffs.effing.dev/render with an API key. The SSE progress stream walks warmup and fires ready with a video URL — GET that, and the MP4 streams back live as it gets rendered. Or pass a pre-signed S3 URL as upload and video gets pushed straight to your bucket. See the @effing/ffs README for the full API.

    terminal
    # 1. Create a render job. FFS fetches the effie URL during warmup.
    $ curl -X POST https://ffs.effing.dev/render \
        -H "Authorization: Bearer $EFFING_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{ "effie": "https://fn.effing.dev/acme/posters/effie/eyJ0..." }'
    { "id": "550e8400-…", "progressUrl": ".../progress" }
    
    # 2. Stream progress (effie → warmup → ready). The `ready` event hands you a video URL.
    $ curl https://ffs.effing.dev/render/550e8400-…/progress
    
    # 3. GET that URL — the render runs now, MP4 bytes stream back as ffmpeg produces them.
    $ curl https://ffs.effing.dev/render/550e8400-…/video -o poster.mp4
  6. 6

    Keep an eye on it

    Every render and run lands in the console: overviews, errors, and usage, all sliceable by tag. And you don’t have to click through charts. The built-in MCP server gives Claude, ChatGPT, or any MCP client read-only access to the same reporting data, so you can just ask. See Connect AI assistants docs.

    claude
    how many renders failed yesterday?
    Effing Cloud · ffs_overview · ffs_list_errors

    Three of 1,214 renders failed yesterday, all with the same error: a background image URL that returns a 404. The error messages point at one missing file.

READY WHEN YOU ARE

Let’s effing go.

Tell us what you have in mind and we’ll tailor a demo just for you.