Record 1440p and 4K, and choose sound and conversion in the node
The Start recording node only offered the game view, 720p and 1080p, and always recorded with sound, converted and imported. The recording from the main menu could already leave those out. - Resolution has 1440p and 4K. As with 720p and 1080p the height is fixed and the width follows the camera, so 16:9 gives 2560x1440 and 3840x2160. - Every resolution is capped at 3840x2160, as the game view already was. A 21:9 camera in 4K would be 5040 px wide, which the encoder levels are not made for. It is scaled down to 3840x1646. - The node has Sound, Convert and Import after conversion, all on by default as in "Start recording...". Import only counts with Convert. An old graph without the inputs records as before. - A released game ignores Convert and Import and downloads the MKV. - Both recordings now hand their upload options the same way, from GameRecorder over PlaySession to RecordingUploads. RecordingUploadOptions moved to core/recording/recording.ts. Tests: - tsc, eslint, Prettier clean - Unit recording and node-catalog: 451 green, recording 29 with 3 new tests and 1 extended - e2e 67 on melektaus-atx: ALL PASSED, 10 checks - Not checked in the browser: a real 4K recording, and the node with its switches off. - The gate ran once on this commit and the next one together. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
65d7bf6a1f
commit
2ba41c1bd0
9 files changed
+151
-51
No files matched your search
@@ -83,6 +83,7 @@ import { EditorRecorder } from './EditorRecorder';
|
||||
import { EditorRecordingDialog } from './EditorRecordingDialog';
|
||||
import { editorRecordingSettings, keepEditorRecordingSettings } from './editorRecordingSettings';
|
||||
import type { MadeRecording } from '../viewport/RecordingTake';
|
||||
import type { RecordingUploadOptions } from '../core/recording/recording';
|
||||
import { ProjectSession } from './ProjectSession';
|
||||
import { ParticlesEditor } from './particles/ParticlesEditor';
|
||||
import { ShaderEditor } from './shader/ShaderEditor';
|
||||
@@ -1573,7 +1574,7 @@ export class Editor implements PlayHost {
|
||||
};
|
||||
}
|
||||
|
||||
recordingSaved(recording: MadeRecording): void {
|
||||
this.recordings.add(recording);
|
||||
recordingSaved(recording: MadeRecording, options: RecordingUploadOptions): void {
|
||||
this.recordings.add(recording, options);
|
||||
}
|
||||
}
|
||||
@@ -7,16 +7,15 @@ import {
|
||||
type CursorShape,
|
||||
} from '../core/recording/cursors';
|
||||
import { editorRecordingPlan, type EditorRecordingSettings } from '../core/recording/editorRecording';
|
||||
import { elapsedText, fitPicture, recordingName } from '../core/recording/recording';
|
||||
import {
|
||||
elapsedText,
|
||||
fitPicture,
|
||||
recordingName,
|
||||
type RecordingUploadOptions,
|
||||
} from '../core/recording/recording';
|
||||
import { renderCount, requestRender, Theme, toHex, ui } from '../ui';
|
||||
import { type FrameSource, type MadeRecording, Take, type TakeInfo } from '../viewport/RecordingTake';
|
||||
|
||||
/** What becomes of a recording on the server, as "Start recording…" asked. */
|
||||
export interface RecordingUploadOptions {
|
||||
convert: boolean;
|
||||
adopt: boolean;
|
||||
}
|
||||
|
||||
/** What the editor recorder needs of the editor. */
|
||||
export interface EditorRecorderHost {
|
||||
/** A line for the editor's notice. */
|
||||
|
||||
@@ -19,6 +19,7 @@ import { onFrame, ui } from '../ui';
|
||||
import { soundLibrary } from '../viewport/SoundLibrary';
|
||||
import { GameRecorder } from '../viewport/GameRecorder';
|
||||
import type { MadeRecording } from '../viewport/RecordingTake';
|
||||
import type { RecordingUploadOptions } from '../core/recording/recording';
|
||||
import { videoLibrary } from '../viewport/VideoLibrary';
|
||||
import { FrameMeter, type FrameTimes } from './frameMeter';
|
||||
import { saveArea } from './saves';
|
||||
@@ -58,8 +59,8 @@ export interface PlayHost {
|
||||
showGame(): void;
|
||||
/** Leave the game view if it is the one on screen. */
|
||||
leaveGame(): void;
|
||||
/** A recording of the game view is made (#405): it goes into the project. */
|
||||
recordingSaved(recording: MadeRecording): void;
|
||||
/** A recording of the game view is made (#405): it goes up, and into the project as the node asked. */
|
||||
recordingSaved(recording: MadeRecording, options: RecordingUploadOptions): void;
|
||||
}
|
||||
|
||||
export class PlaySession {
|
||||
@@ -97,7 +98,7 @@ export class PlaySession {
|
||||
this.world?.log.push(line);
|
||||
console.warn('[recording]', line);
|
||||
},
|
||||
saved: (recording) => host.recordingSaved(recording),
|
||||
saved: (recording, options) => host.recordingSaved(recording, options),
|
||||
});
|
||||
// An object picked during a run is looked at now: the hierarchy has to list it to show it picked.
|
||||
state.on('selection', () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { UploadedVideo } from '../core/store/VideoStore';
|
||||
import type { MadeRecording } from '../viewport/RecordingTake';
|
||||
import type { RecordingUploadOptions } from './EditorRecorder';
|
||||
import type { RecordingUploadOptions } from '../core/recording/recording';
|
||||
import { adoptVideo, type VideoImportDeps } from './videoImport';
|
||||
|
||||
/** How often the server is asked whether a recording is converted, as the video picker does. */
|
||||
@@ -24,8 +24,8 @@ export interface RecordingUpload {
|
||||
* Brings a recording of the game view (#405) or of the editor into the project: up to the server,
|
||||
* which converts it like any video, then an asset named after the recording once it is ready. Only
|
||||
* while the editor is not playing: a run plays a copy of the project that is thrown away, and so
|
||||
* would the asset be. An editor recording may stop short of either step ("Start recording…"): it
|
||||
* is always uploaded, and the video picker has it.
|
||||
* would the asset be. A recording may stop short of either step, as "Start recording…" or the node
|
||||
* asked: it is always uploaded, and the video picker has it.
|
||||
*/
|
||||
export class RecordingUploads {
|
||||
private readonly uploads: RecordingUpload[] = [];
|
||||
|
||||
Reference in new issue
Block a user