|
1 | 1 | --- |
2 | | -title: 4K Rendering |
3 | | -description: "Render any composition to 4K (3840×2160) without rewriting it — the CLI supersamples a 1080p composition via Chrome's device scale factor." |
| 2 | +title: Render in 4K |
| 3 | +description: Author at 4K or supersample an existing composition at render time. |
4 | 4 | --- |
5 | 5 |
|
6 | | -Hyperframes renders to 4K (3840×2160) two ways. Both produce a true 4K MP4; pick the one that matches your project. |
7 | | - |
8 | | -<CardGroup cols={2}> |
9 | | - <Card title="Author at 4K" icon="ruler"> |
10 | | - Scaffold the project at 4K so the composition is laid out at 4K natively. Best when you want crisp 4K-native typography and assets. |
11 | | - ```bash |
12 | | - npx hyperframes init my-video --resolution 4k |
13 | | - ``` |
14 | | - </Card> |
15 | | - <Card title="Supersample at render" icon="up-right-and-down-left-from-center"> |
16 | | - Keep your existing 1080p composition. Pass `--resolution 4k` at render time and Chrome renders at 2× DPR so the screenshot lands at 4K. |
17 | | - ```bash |
18 | | - npx hyperframes render --resolution 4k --output 4k.mp4 |
19 | | - ``` |
20 | | - </Card> |
21 | | -</CardGroup> |
22 | | - |
23 | | -## Quickstart |
24 | | - |
25 | | -<Steps> |
26 | | - <Step title="Render an existing project at 4K"> |
27 | | - ```bash Terminal |
28 | | - npx hyperframes render --resolution 4k --output my-video-4k.mp4 |
29 | | - ``` |
30 | | - |
31 | | - The composition's `data-width` / `data-height` are unchanged. Chrome's `deviceScaleFactor` is set to `2`, so the captured screenshot for each frame is 3840×2160. ffmpeg auto-detects the dimensions from the screenshot stream and encodes at 4K. |
32 | | - </Step> |
33 | | - <Step title="Or scaffold a new project at 4K"> |
34 | | - ```bash Terminal |
35 | | - npx hyperframes init my-video --resolution 4k |
36 | | - ``` |
37 | | - |
38 | | - Every scaffolded HTML file is patched in place: `data-width="3840"`, `data-height="2160"`, `data-resolution="landscape-4k"`, `#stage` CSS dimensions, and the `<meta viewport>` tag. |
39 | | - </Step> |
40 | | - <Step title="Verify the output is 4K"> |
41 | | - ```bash Terminal |
42 | | - ffprobe -v error -select_streams v:0 -show_entries stream=width,height my-video-4k.mp4 |
43 | | - ``` |
44 | | - |
45 | | - Expected: |
46 | | - ``` |
47 | | - width=3840 |
48 | | - height=2160 |
49 | | - ``` |
50 | | - </Step> |
51 | | -</Steps> |
52 | | - |
53 | | -## Resolution presets |
54 | | - |
55 | | -`--resolution` accepts these values on both `init` and `render`: |
56 | | - |
57 | | -| Preset | Dimensions | Aliases | |
58 | | -|--------|-----------|---------| |
59 | | -| `landscape` | 1920×1080 | `1080p`, `hd` | |
60 | | -| `portrait` | 1080×1920 | `1080p-portrait` | |
61 | | -| `square` | 1080×1080 | `1080p-square`, `square-1080p` | |
62 | | -| `landscape-4k` | 3840×2160 | `4k`, `uhd` | |
63 | | -| `portrait-4k` | 2160×3840 | `4k-portrait` | |
64 | | -| `square-4k` | 2160×2160 | `4k-square` | |
65 | | - |
66 | | -Examples: |
67 | | - |
68 | | -```bash Terminal |
69 | | -npx hyperframes render --resolution 4k # landscape 4K |
70 | | -npx hyperframes render --resolution portrait-4k # vertical 4K (TikTok / Reels at max quality) |
71 | | -npx hyperframes render --resolution 1080p # explicit 1080p (no-op on 1080p compositions) |
72 | | -``` |
73 | | - |
74 | | -## How `--resolution` works (supersampling) |
75 | | - |
76 | | -The composition stays at its authored dimensions. Hyperframes computes a `deviceScaleFactor` from the ratio of output to composition dimensions and passes it to Chrome: |
77 | | - |
78 | | -| Composition | `--resolution` | `deviceScaleFactor` | Output | |
79 | | -|-------------|---------------|--------------------|--------| |
80 | | -| 1920×1080 | `4k` | 2 | 3840×2160 | |
81 | | -| 1080×1920 | `portrait-4k` | 2 | 2160×3840 | |
82 | | -| 3840×2160 | `4k` | 1 (no-op) | 3840×2160 | |
83 | | - |
84 | | -Chrome then renders the page at the higher DPR — effectively rendering each CSS pixel as 2×2 device pixels — so the captured screenshot is at the requested resolution. |
| 6 | +## Render an existing project in 4K |
85 | 7 |
|
86 | | -<Tip> |
87 | | - This approach is intentionally simple — no composition edits, no second authoring pass. The tradeoff: 4K renders take roughly 4× as long per frame because there are 4× the pixels to capture and encode. |
88 | | -</Tip> |
89 | | - |
90 | | -## What scales, what doesn't |
91 | | - |
92 | | -Supersampling re-renders the page at higher DPR. That genuinely helps anything the browser rasterizes from a vector or high-resolution source, and does nothing for content already locked to a fixed pixel grid. Knowing which is which sets correct expectations before a 4K render: |
| 8 | +```bash |
| 9 | +npx hyperframes render --resolution 4k --output final-4k.mp4 |
| 10 | +``` |
93 | 11 |
|
94 | | -| Asset type | Behavior at `--resolution 4k` | |
95 | | -|------------|------------------------------| |
96 | | -| Text (HTML, SVG `<text>`, web fonts) | ✅ **Re-rasterized at 4K.** Glyphs are vector and the browser shapes/rasterizes them at the new DPR. Crisp at any scale. | |
97 | | -| SVG / vector graphics | ✅ **Re-rasterized at 4K.** Same story as text — paths are vector. | |
98 | | -| CSS shapes, gradients, borders, shadows | ✅ **Re-rasterized at 4K.** Browser-generated raster. | |
99 | | -| Images with intrinsic dimensions ≥ 4K | ✅ **Full benefit.** A 3840×2160 source serves all the detail. | |
100 | | -| Images smaller than 4K (e.g. a 1920×1080 PNG) | ⚠️ **No new detail.** Browser upscales the source bitmap; output is no sharper than rendering at 1080p and upscaling externally — but no worse either. | |
101 | | -| `<video>` elements | ❌ **Locked to source resolution.** A 1080p MP4 stays 1080p; the supersample only helps the surrounding DOM. Encode source video at the target resolution if you need 4K throughout. | |
102 | | -| `<canvas>` (2D and WebGL) | ❌ **Locked to canvas's intrinsic dimensions.** `<canvas width="1920" height="1080">` is a 1080p bitmap regardless of DPR. To render canvas content at 4K, multiply `canvas.width` / `canvas.height` by your target DPR and scale the drawing context (`ctx.scale(2, 2)` for a 2× canvas with the same logical layout). | |
103 | | -| Pre-rendered video frames injected by the engine | ❌ **Locked to extraction resolution.** When the producer pre-extracts `<video>` frames via ffmpeg, they're decoded at the source video's dimensions. | |
| 12 | +HyperFrames keeps the composition's layout unchanged and captures it at a higher device-pixel ratio. A 1920×1080 composition becomes a 3840×2160 file. |
104 | 13 |
|
105 | | -**Rule of thumb**: if the asset is *vector or generated by the browser*, supersampling helps. If it's a *bitmap with fixed pixel dimensions* (video, canvas, low-res PNG), it doesn't — author it at the target resolution instead. |
| 14 | +Use the matching preset for portrait or square work: |
106 | 15 |
|
107 | | -## Constraints |
| 16 | +| Preset | Output | |
| 17 | +| --- | --- | |
| 18 | +| `4k` or `landscape-4k` | 3840×2160 | |
| 19 | +| `portrait-4k` | 2160×3840 | |
| 20 | +| `square-4k` | 2160×2160 | |
108 | 21 |
|
109 | | -`--resolution` enforces three guards before any frames are captured. If any fail, the render exits before doing work. |
| 22 | +## Author a project at 4K |
110 | 23 |
|
111 | | -### Aspect ratio must match |
| 24 | +If the project should use a 4K canvas from the start: |
112 | 25 |
|
113 | 26 | ```bash |
114 | | -# OK — both landscape |
115 | | -hyperframes render --resolution 4k # composition is 1920×1080 |
116 | | - |
117 | | -# Error — composition is landscape, target is portrait |
118 | | -hyperframes render --resolution portrait-4k # composition is 1920×1080 |
119 | | -# → outputResolution portrait-4k (2160×3840) does not match the aspect ratio |
120 | | -# of the composition (1920×1080). Pick a preset whose orientation matches. |
| 27 | +npx hyperframes init my-video --resolution 4k |
121 | 28 | ``` |
122 | 29 |
|
123 | | -### The scale must be an integer |
124 | | - |
125 | | -The width ratio (output ÷ composition) must be a positive integer. 1080p → 4K is exactly `2×`. 720p → 4K would be `3×` and works. Non-integer scales like 900p → 4K (`2.4×`) introduce aliasing on subpixel-positioned text — Hyperframes refuses rather than producing a blurry render. |
126 | | - |
127 | | -### Downsampling is not supported |
128 | | - |
129 | | -`--resolution` only supersamples. A 4K composition cannot be downsampled to 1080p with this flag — render at the composition's native resolution and downscale separately with ffmpeg if needed. |
130 | | - |
131 | | -### Not yet supported with `--hdr` |
| 30 | +Choose this when canvas or WebGL code, fixed-resolution media, or layout decisions need to know the final pixel dimensions while you author. |
132 | 31 |
|
133 | | -The HDR layered compositor processes pixel buffers at composition dimensions; supersample + HDR would need parallel scaling for those buffers. The combination is rejected with a clear error message. Render in two passes if you need both: HDR at composition resolution, then upscale separately. |
| 32 | +## What gets sharper |
134 | 33 |
|
135 | | -## Performance |
| 34 | +| Content | Result when supersampled | |
| 35 | +| --- | --- | |
| 36 | +| HTML text, SVG, CSS shapes, gradients | Re-rasterized at 4K | |
| 37 | +| High-resolution images | Use their available source detail | |
| 38 | +| 1080p images and video | Scaled up; no new source detail | |
| 39 | +| `<canvas>` and WebGL | Limited by the canvas's intrinsic dimensions | |
136 | 40 |
|
137 | | -A 1080p → 4K supersample is roughly 4× more pixels to capture, encode, and write. Expect: |
| 41 | +For a fully sharp 4K result, use 4K source media and size canvas/WebGL buffers for the target resolution. |
138 | 42 |
|
139 | | -- **Per-frame capture**: 3–4× slower (Chrome paints 4× the pixels and the screenshot transfer is 4× larger) |
140 | | -- **Encoding**: 2–3× slower (depends on codec; H.264 scales sublinearly with resolution) |
141 | | -- **Memory**: bounded — the engine's frame data-URI cache is byte-budgeted (default 1500 MB per worker, configurable via `PRODUCER_FRAME_DATA_URI_CACHE_BYTES_MB`) |
142 | | -- **Output file size**: at the default CRF, expect 3–5× the file size of the 1080p render. Pass `--video-bitrate 25M` (or higher) for predictable file sizes. |
143 | | - |
144 | | -For a 4K render of a 30-second composition, plan on a few minutes of wall time on a modern laptop. Add `--workers 4` (or more) on a render box for parallel capture. |
| 43 | +## Constraints |
145 | 44 |
|
146 | | -## Studio support |
| 45 | +`--resolution` only works when: |
147 | 46 |
|
148 | | -The Renders panel in Studio includes a resolution dropdown next to the format and quality selectors. Pick `4K` (or `4K ↕` for portrait) and hit **Export** — the same supersampling path runs as the CLI flag, no composition edits required. |
| 47 | +- the preset has the same aspect ratio as the composition; |
| 48 | +- the target is an integer multiple of the authored dimensions; |
| 49 | +- the target is not smaller than the composition; |
| 50 | +- the output is MP4 rather than an alpha format; |
| 51 | +- HDR is not forced for the same render. |
149 | 52 |
|
150 | | -The dropdown defaults to `Auto` (render at the composition's authored size). Available presets: |
| 53 | +HyperFrames checks these conditions before opening the browser. Render at the composition's native size and resize separately when a combination is unsupported. |
151 | 54 |
|
152 | | -- **Auto** — composition's native dimensions |
153 | | -- **1080p ↔** / **1080p ↕** — 1920×1080 / 1080×1920 |
154 | | -- **4K ↔** / **4K ↕** — 3840×2160 / 2160×3840 |
| 55 | +## Verify the file |
155 | 56 |
|
156 | | -The resolution applies per render, not per project — your composition files are unchanged. The same [constraints](#constraints) apply; when the producer rejects a combination, the failure surfaces in the Studio render queue. |
| 57 | +```bash |
| 58 | +ffprobe -v error -select_streams v:0 \ |
| 59 | + -show_entries stream=width,height final-4k.mp4 |
| 60 | +``` |
157 | 61 |
|
158 | | -You can also drive resolution from the CLI: |
| 62 | +For landscape 4K, the output should report `3840` by `2160`. |
159 | 63 |
|
160 | | -- **New project**: `hyperframes init my-video --resolution 4k` |
161 | | -- **Existing project**: `hyperframes render --resolution 4k --output 4k.mp4` |
| 64 | +4K captures four times as many pixels as 1080p, so expect more render time, memory use, and output data. Start with `--quality draft` for review, then render the approved version at the quality you need. |
162 | 65 |
|
163 | | -## See also |
| 66 | +## Related topics |
164 | 67 |
|
165 | | -- [`render` CLI reference](/packages/cli#render) — every render flag including `--video-bitrate` and `--crf` |
166 | | -- [`init` CLI reference](/packages/cli#init) — the `--resolution` flag at scaffold time |
167 | | -- [HDR Rendering](/guides/hdr) — color pipeline guide; HDR + 4K is not yet a supported combination |
| 68 | +- [Render from the command line](/guides/rendering) |
| 69 | +- [Improve render performance](/guides/performance) |
| 70 | +- [Deliver an HDR project](/guides/hdr) |
0 commit comments