fragment-tools 0.2.9 → 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -6
- package/src/cli/createConfig.js +38 -19
- package/src/cli/plugins/hot-shader-replacement.js +0 -5
- package/src/cli/plugins/save.js +7 -2
- package/src/cli/run.js +27 -6
- package/src/client/app/lib/canvas-recorder/CanvasRecorder.js +3 -1
- package/src/client/app/lib/canvas-recorder/GIFRecorder.js +11 -1
- package/src/client/app/lib/canvas-recorder/MediaBunnyRecorder.js +97 -0
- package/src/client/app/modules/Exports.svelte +28 -4
- package/src/client/app/state/exports.svelte.js +40 -2
- package/src/client/app/state/rendering.svelte.js +1 -1
- package/src/client/app/ui/Field.svelte +7 -3
- package/src/client/app/ui/FieldSection.svelte +1 -1
- package/src/client/app/ui/LayoutBuild.svelte +1 -1
- package/src/client/app/ui/SketchRenderer.svelte +5 -1
- package/src/client/app/ui/fields/CheckboxInput.svelte +9 -7
- package/src/client/app/ui/fields/ImageInput.svelte +33 -15
- package/src/client/app/ui/fields/Select.svelte +2 -1
- package/src/client/app/utils/canvas.utils.js +21 -19
- package/src/index.js +12 -0
- package/src/types/config.d.ts +6 -0
- package/src/types/index.d.ts +1 -0
- package/src/types/props.d.ts +32 -5
- package/.changeset/README.md +0 -8
- package/.changeset/config.json +0 -11
- package/.prettierignore +0 -5
- package/.prettierrc +0 -25
- package/CHANGELOG.md +0 -10
- package/src/client/app/lib/canvas-recorder/MP4Recorder.js +0 -44
- package/src/client/app/lib/canvas-recorder/WebMRecorder.js +0 -29
- package/src/client/app/lib/canvas-recorder/mp4.js +0 -1654
- package/src/client/app/lib/canvas-recorder/mp4.wasm +0 -0
- package/src/client/public/preview.html +0 -59
|
@@ -4,7 +4,13 @@
|
|
|
4
4
|
import FieldInputRow from './FieldInputRow.svelte';
|
|
5
5
|
import TextInput from './TextInput.svelte';
|
|
6
6
|
|
|
7
|
-
let {
|
|
7
|
+
let {
|
|
8
|
+
value,
|
|
9
|
+
context = null,
|
|
10
|
+
key = '',
|
|
11
|
+
onchange,
|
|
12
|
+
disabled = false,
|
|
13
|
+
} = $props();
|
|
8
14
|
|
|
9
15
|
/** @type {HTMLImageElement} */
|
|
10
16
|
let img;
|
|
@@ -24,7 +30,7 @@
|
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
let reader = new FileReader();
|
|
27
|
-
let dragover = false;
|
|
33
|
+
let dragover = $state(false);
|
|
28
34
|
|
|
29
35
|
function handleUpload(event) {
|
|
30
36
|
event.preventDefault();
|
|
@@ -44,6 +50,7 @@
|
|
|
44
50
|
reader.onload = null;
|
|
45
51
|
|
|
46
52
|
value = e.target.result;
|
|
53
|
+
onchange(value);
|
|
47
54
|
};
|
|
48
55
|
reader.readAsDataURL(file);
|
|
49
56
|
|
|
@@ -67,33 +74,31 @@
|
|
|
67
74
|
|
|
68
75
|
<div
|
|
69
76
|
class="img-container"
|
|
77
|
+
role="group"
|
|
78
|
+
aria-label="Drop an image here to upload"
|
|
70
79
|
class:dragover
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
80
|
+
ondragover={handleDragover}
|
|
81
|
+
ondragleave={handleDragleave}
|
|
82
|
+
ondrop={handleUpload}
|
|
74
83
|
>
|
|
75
84
|
<FieldInputRow --grid-template-columns="1fr 0.5fr">
|
|
76
85
|
<div class="row">
|
|
77
|
-
<div class="preview"
|
|
86
|
+
<div class="preview">
|
|
78
87
|
<img class="img" src="" alt="" bind:this={img} />
|
|
88
|
+
<button class="preview-button" onclick={handleClick}>
|
|
89
|
+
<span class="visually-hidden">Upload</span>
|
|
90
|
+
</button>
|
|
79
91
|
<input
|
|
80
92
|
class="input"
|
|
81
93
|
type="file"
|
|
82
94
|
bind:this={input}
|
|
83
|
-
|
|
95
|
+
onchange={handleUpload}
|
|
84
96
|
disabled={disabled ? 'disabled' : null}
|
|
85
97
|
/>
|
|
86
98
|
</div>
|
|
87
99
|
<TextInput disabled value={displayUrl} />
|
|
88
100
|
</div>
|
|
89
|
-
<ButtonInput
|
|
90
|
-
label="change"
|
|
91
|
-
on:click={handleClick}
|
|
92
|
-
on:dragover={handleDragover}
|
|
93
|
-
on:dragleave={handleDragleave}
|
|
94
|
-
on:drop={handleUpload}
|
|
95
|
-
{disabled}
|
|
96
|
-
/>
|
|
101
|
+
<ButtonInput label="change" onclick={handleClick} {disabled} />
|
|
97
102
|
</FieldInputRow>
|
|
98
103
|
</div>
|
|
99
104
|
|
|
@@ -103,6 +108,8 @@
|
|
|
103
108
|
}
|
|
104
109
|
|
|
105
110
|
.preview {
|
|
111
|
+
position: relative;
|
|
112
|
+
|
|
106
113
|
width: calc(var(--fragment-input-height) * 1);
|
|
107
114
|
height: calc(var(--fragment-input-height) * 1);
|
|
108
115
|
display: grid;
|
|
@@ -116,6 +123,17 @@
|
|
|
116
123
|
overflow: hidden;
|
|
117
124
|
}
|
|
118
125
|
|
|
126
|
+
.preview-button {
|
|
127
|
+
position: absolute;
|
|
128
|
+
top: 0;
|
|
129
|
+
left: 0;
|
|
130
|
+
|
|
131
|
+
width: 100%;
|
|
132
|
+
height: 100%;
|
|
133
|
+
|
|
134
|
+
opacity: 0;
|
|
135
|
+
}
|
|
136
|
+
|
|
119
137
|
.row {
|
|
120
138
|
display: grid;
|
|
121
139
|
grid-template-columns: 20px auto;
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
.select {
|
|
119
|
-
padding: 0
|
|
119
|
+
padding: 0 18px 0 var(--padding, 6px);
|
|
120
120
|
|
|
121
121
|
width: 100%;
|
|
122
122
|
|
|
@@ -126,6 +126,7 @@
|
|
|
126
126
|
outline: 0;
|
|
127
127
|
background-color: transparent;
|
|
128
128
|
opacity: 1;
|
|
129
|
+
text-overflow: ellipsis;
|
|
129
130
|
}
|
|
130
131
|
|
|
131
132
|
.select-input:not(.disabled) .select {
|
|
@@ -3,10 +3,9 @@ https://github.com/mattdesl/canvas-sketch/blob/24f6bb2bbdfdfd72a698a0b8a0962ad84
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { VIDEO_FORMATS } from '../state/exports.svelte';
|
|
6
|
-
import WebMRecorder from '../lib/canvas-recorder/WebMRecorder';
|
|
7
|
-
import MP4Recorder from '../lib/canvas-recorder/MP4Recorder';
|
|
8
6
|
import GIFRecorder from '../lib/canvas-recorder/GIFRecorder';
|
|
9
7
|
import FrameRecorder from '../lib/canvas-recorder/FrameRecorder';
|
|
8
|
+
import MediaBunnyRecorder from '../lib/canvas-recorder/MediaBunnyRecorder';
|
|
10
9
|
import { exportCanvas } from '../lib/canvas-recorder/utils';
|
|
11
10
|
import { map } from './math.utils';
|
|
12
11
|
import { createDataURLFromBlob, saveFiles } from './file.utils';
|
|
@@ -101,28 +100,21 @@ export async function screenshotCanvas(
|
|
|
101
100
|
}
|
|
102
101
|
}
|
|
103
102
|
|
|
104
|
-
function
|
|
105
|
-
let recorder = new
|
|
103
|
+
function record(canvas, options) {
|
|
104
|
+
let recorder = new MediaBunnyRecorder(canvas, options);
|
|
106
105
|
recorder.start();
|
|
107
106
|
|
|
108
107
|
return recorder;
|
|
109
108
|
}
|
|
110
109
|
|
|
111
|
-
function
|
|
112
|
-
let recorder = new MP4Recorder(canvas, options);
|
|
113
|
-
recorder.start();
|
|
114
|
-
|
|
115
|
-
return recorder;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function recordCanvasGIF(canvas, options) {
|
|
110
|
+
function recordGIF(canvas, options) {
|
|
119
111
|
let recorder = new GIFRecorder(canvas, options);
|
|
120
112
|
recorder.start();
|
|
121
113
|
|
|
122
114
|
return recorder;
|
|
123
115
|
}
|
|
124
116
|
|
|
125
|
-
function
|
|
117
|
+
function recordFrames(canvas, options) {
|
|
126
118
|
let recorder = new FrameRecorder(canvas, options);
|
|
127
119
|
recorder.start();
|
|
128
120
|
|
|
@@ -138,6 +130,7 @@ export function recordCanvas(
|
|
|
138
130
|
duration = Infinity,
|
|
139
131
|
quality = 100,
|
|
140
132
|
pattern = defaultFilenamePattern,
|
|
133
|
+
codec,
|
|
141
134
|
exportDir,
|
|
142
135
|
imageEncoding,
|
|
143
136
|
onStart = () => {},
|
|
@@ -189,6 +182,7 @@ export function recordCanvas(
|
|
|
189
182
|
|
|
190
183
|
const options = {
|
|
191
184
|
framerate,
|
|
185
|
+
format,
|
|
192
186
|
duration,
|
|
193
187
|
quality,
|
|
194
188
|
onStart,
|
|
@@ -198,14 +192,22 @@ export function recordCanvas(
|
|
|
198
192
|
|
|
199
193
|
let recorder;
|
|
200
194
|
|
|
201
|
-
if (
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
195
|
+
if (
|
|
196
|
+
[
|
|
197
|
+
VIDEO_FORMATS.MKV,
|
|
198
|
+
VIDEO_FORMATS.MOV,
|
|
199
|
+
VIDEO_FORMATS.MP4,
|
|
200
|
+
VIDEO_FORMATS.WEBM,
|
|
201
|
+
].includes(format)
|
|
202
|
+
) {
|
|
203
|
+
recorder = record(canvas, {
|
|
204
|
+
...options,
|
|
205
|
+
codec,
|
|
206
|
+
});
|
|
205
207
|
} else if (format === VIDEO_FORMATS.GIF) {
|
|
206
|
-
recorder =
|
|
208
|
+
recorder = recordGIF(canvas, options);
|
|
207
209
|
} else if (format === VIDEO_FORMATS.FRAMES) {
|
|
208
|
-
recorder =
|
|
210
|
+
recorder = recordFrames(canvas, {
|
|
209
211
|
...options,
|
|
210
212
|
imageEncoding,
|
|
211
213
|
});
|
package/src/index.js
ADDED
package/src/types/index.d.ts
CHANGED
package/src/types/props.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ type BaseProp<Value, Params, Type> = {
|
|
|
3
3
|
params?: Params;
|
|
4
4
|
type?: Type;
|
|
5
5
|
hidden?: boolean;
|
|
6
|
-
displayName?: string;
|
|
6
|
+
displayName?: string | null;
|
|
7
7
|
folder?: string;
|
|
8
8
|
group?: string;
|
|
9
9
|
onChange?: PropOnChange<Value, Params>;
|
|
@@ -25,11 +25,37 @@ type NumberProp = BaseProp<
|
|
|
25
25
|
{ disabled?: boolean; step?: number } | { min: number; max: number },
|
|
26
26
|
'number'
|
|
27
27
|
>;
|
|
28
|
-
|
|
28
|
+
|
|
29
|
+
type VecArray =
|
|
29
30
|
| [number, number]
|
|
30
31
|
| [number, number, number]
|
|
31
|
-
| [number, number, number, number]
|
|
32
|
-
|
|
32
|
+
| [number, number, number, number];
|
|
33
|
+
|
|
34
|
+
type VecObject = Record<string, number> & { [key: number]: never };
|
|
35
|
+
|
|
36
|
+
type VecValue = VecArray | VecObject;
|
|
37
|
+
|
|
38
|
+
type VecArrayParams<V extends VecArray> = {
|
|
39
|
+
min: { [K in keyof V]: number };
|
|
40
|
+
max: { [K in keyof V]: number };
|
|
41
|
+
step?: { [K in keyof V]: number };
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
type VecObjectParams<V extends VecObject> = {
|
|
45
|
+
min: { [K in keyof V]: number };
|
|
46
|
+
max: { [K in keyof V]: number };
|
|
47
|
+
step?: { [K in keyof V]: number };
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
type VecParams<V extends VecValue> = V extends readonly number[]
|
|
51
|
+
? VecArrayParams<V>
|
|
52
|
+
: V extends Record<string, number>
|
|
53
|
+
? VecObjectParams<V>
|
|
54
|
+
: never;
|
|
55
|
+
|
|
56
|
+
type VecProp<V extends VecValue = VecValue> = BaseProp<
|
|
57
|
+
V,
|
|
58
|
+
{ locked?: boolean } | VecParams<V>,
|
|
33
59
|
'vec'
|
|
34
60
|
>;
|
|
35
61
|
type CheckboxProp = BaseProp<boolean, never, 'checkbox'>;
|
|
@@ -50,7 +76,8 @@ type ImageProp = BaseProp<string, never, 'image'>;
|
|
|
50
76
|
type Prop =
|
|
51
77
|
| SelectProp
|
|
52
78
|
| NumberProp
|
|
53
|
-
| VecProp
|
|
79
|
+
| VecProp<VecObject>
|
|
80
|
+
| VecProp<VecArray>
|
|
54
81
|
| CheckboxProp
|
|
55
82
|
| TextProp
|
|
56
83
|
| ListProp
|
package/.changeset/README.md
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
# Changesets
|
|
2
|
-
|
|
3
|
-
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
|
4
|
-
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
|
5
|
-
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
|
6
|
-
|
|
7
|
-
We have a quick list of common questions to get you started engaging with this project in
|
|
8
|
-
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
package/.changeset/config.json
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
|
|
3
|
-
"changelog": ["@svitejs/changesets-changelog-github-compact", { "repo": "raphaelameaume/fragment"}],
|
|
4
|
-
"commit": false,
|
|
5
|
-
"fixed": [],
|
|
6
|
-
"linked": [],
|
|
7
|
-
"access": "restricted",
|
|
8
|
-
"baseBranch": "main",
|
|
9
|
-
"updateInternalDependencies": "patch",
|
|
10
|
-
"ignore": []
|
|
11
|
-
}
|
package/.prettierignore
DELETED
package/.prettierrc
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"semi": true,
|
|
3
|
-
"tabWidth": 4,
|
|
4
|
-
"useTabs": true,
|
|
5
|
-
"singleQuote": true,
|
|
6
|
-
"printWidth": 80,
|
|
7
|
-
"bracketSpacing": true,
|
|
8
|
-
"trailingComma": "all",
|
|
9
|
-
"plugins": ["prettier-plugin-svelte"],
|
|
10
|
-
"overrides": [
|
|
11
|
-
{
|
|
12
|
-
"files": ["README.md", "packages/*/README.md", "**/package.json"],
|
|
13
|
-
"options": {
|
|
14
|
-
"useTabs": false,
|
|
15
|
-
"tabWidth": 2
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
"files": ["docs/**/*.md"],
|
|
20
|
-
"options": {
|
|
21
|
-
"printWidth": 60
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
]
|
|
25
|
-
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import loadMP4Module, { isWebCodecsSupported } from './mp4.js';
|
|
2
|
-
import CanvasRecorder from './CanvasRecorder';
|
|
3
|
-
|
|
4
|
-
let MP4;
|
|
5
|
-
|
|
6
|
-
class MP4Recorder extends CanvasRecorder {
|
|
7
|
-
static loaded = false;
|
|
8
|
-
static isSupported = true;
|
|
9
|
-
|
|
10
|
-
constructor(canvas, options) {
|
|
11
|
-
super(canvas, options);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
async load() {
|
|
15
|
-
if (!MP4Recorder.loaded) {
|
|
16
|
-
MP4 = await loadMP4Module();
|
|
17
|
-
|
|
18
|
-
MP4Recorder.loaded = true;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
this.encoder = MP4.createWebCodecsEncoder({
|
|
22
|
-
width: this.canvas.width,
|
|
23
|
-
height: this.canvas.height,
|
|
24
|
-
fps: this.framerate,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async tick() {
|
|
29
|
-
const bitmap = await window.createImageBitmap(this.canvas);
|
|
30
|
-
|
|
31
|
-
// Add bitmap to encoder
|
|
32
|
-
await this.encoder.addFrame(bitmap);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async end() {
|
|
36
|
-
const buffer = await this.encoder.end();
|
|
37
|
-
|
|
38
|
-
this.result = new Blob([buffer], { type: 'video/mp4' });
|
|
39
|
-
|
|
40
|
-
super.end();
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export default MP4Recorder;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import WebMWriter from 'webm-writer';
|
|
2
|
-
import { map } from '../../utils/math.utils';
|
|
3
|
-
import CanvasRecorder from './CanvasRecorder';
|
|
4
|
-
|
|
5
|
-
class WebMRecorder extends CanvasRecorder {
|
|
6
|
-
start() {
|
|
7
|
-
const quality = map(this.quality, 1, 100, 0, 0.99999);
|
|
8
|
-
|
|
9
|
-
this.writer = new WebMWriter({
|
|
10
|
-
quality,
|
|
11
|
-
frameRate: this.framerate,
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
super.start();
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
tick() {
|
|
18
|
-
this.writer.addFrame(this.canvas);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async end() {
|
|
22
|
-
this.result = await this.writer.complete();
|
|
23
|
-
this.writer = null;
|
|
24
|
-
|
|
25
|
-
super.end();
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export default WebMRecorder;
|