@effing/create 0.17.1 → 0.18.0
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 +1 -1
- package/template/app/annies/text-typewriter.annie.tsx +13 -5
- package/template/app/effies/simple-slideshow.effie.tsx +2 -2
- package/template/app/fonts.server.ts +1 -1
- package/template/app/routes/an.$segment.tsx +2 -0
- package/template/app/routes/pan.$annieId.tsx +1 -1
- package/template/app/urls.server.ts +16 -8
- package/template/package.json +9 -13
- package/template/vite.config.ts +4 -1
- package/template/app/pool.server.ts +0 -8
- package/template/vite.config.satori.ts +0 -34
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { interBold, loadFonts } from "~/fonts.server";
|
|
3
3
|
import { tween } from "@effing/tween";
|
|
4
|
-
import {
|
|
4
|
+
import { createCanvas, renderReactElement } from "@effing/canvas";
|
|
5
5
|
import type { AnnieRendererArgs } from ".";
|
|
6
6
|
|
|
7
7
|
export const propsSchema = z.object({
|
|
@@ -50,7 +50,10 @@ export async function* renderer({
|
|
|
50
50
|
yield* tween(typingFrameCount, async ({ lower: p }) => {
|
|
51
51
|
const charsShown = Math.floor(p * text.length);
|
|
52
52
|
const textToShow = text.slice(0, charsShown);
|
|
53
|
-
|
|
53
|
+
const canvas = createCanvas(width, height);
|
|
54
|
+
const ctx = canvas.getContext("2d");
|
|
55
|
+
await renderReactElement(
|
|
56
|
+
ctx,
|
|
54
57
|
<TextTypewriterOverlay
|
|
55
58
|
text={textToShow}
|
|
56
59
|
fontSize={fontSize}
|
|
@@ -60,14 +63,18 @@ export async function* renderer({
|
|
|
60
63
|
verticalAlignment={verticalAlignment}
|
|
61
64
|
cursorShown={true}
|
|
62
65
|
/>,
|
|
63
|
-
{
|
|
66
|
+
{ fonts },
|
|
64
67
|
);
|
|
68
|
+
return canvas.encode("png");
|
|
65
69
|
});
|
|
66
70
|
|
|
67
71
|
// Blinking cursor phase
|
|
68
72
|
yield* tween(blinkingFrameCount, async ({ lower: p }) => {
|
|
69
73
|
const cursorShown = Math.floor(p * 5) % 2 === 1;
|
|
70
|
-
|
|
74
|
+
const canvas = createCanvas(width, height);
|
|
75
|
+
const ctx = canvas.getContext("2d");
|
|
76
|
+
await renderReactElement(
|
|
77
|
+
ctx,
|
|
71
78
|
<TextTypewriterOverlay
|
|
72
79
|
text={text}
|
|
73
80
|
fontSize={fontSize}
|
|
@@ -77,8 +84,9 @@ export async function* renderer({
|
|
|
77
84
|
verticalAlignment={verticalAlignment}
|
|
78
85
|
cursorShown={cursorShown}
|
|
79
86
|
/>,
|
|
80
|
-
{
|
|
87
|
+
{ fonts },
|
|
81
88
|
);
|
|
89
|
+
return canvas.encode("png");
|
|
82
90
|
});
|
|
83
91
|
}
|
|
84
92
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { effieData, effieSegment } from "@effing/effie";
|
|
3
|
-
import { annieUrl,
|
|
3
|
+
import { annieUrl, pngUrlFromReactElement } from "~/urls.server";
|
|
4
4
|
import type { EffieRendererArgs } from ".";
|
|
5
5
|
import { loadFonts, interSemiBold } from "~/fonts.server";
|
|
6
6
|
import type { PhotoZoomProps } from "~/annies/photo-zoom.annie";
|
|
@@ -49,7 +49,7 @@ export async function renderer({
|
|
|
49
49
|
const fonts = await loadFonts([interSemiBold]);
|
|
50
50
|
|
|
51
51
|
// Generate cover from first slide
|
|
52
|
-
const cover = await
|
|
52
|
+
const cover = await pngUrlFromReactElement(
|
|
53
53
|
<div
|
|
54
54
|
style={{
|
|
55
55
|
width,
|
|
@@ -23,10 +23,12 @@ export async function loader({ params, request }: Route.LoaderArgs) {
|
|
|
23
23
|
const width = parseInt(url.searchParams.get("w") || "1080", 10);
|
|
24
24
|
const height = parseInt(url.searchParams.get("h") || "1080", 10);
|
|
25
25
|
|
|
26
|
+
const noCache = url.searchParams.get("cache") === "no";
|
|
26
27
|
const frames = renderer({ props, width, height });
|
|
27
28
|
|
|
28
29
|
return annieResponse(frames, {
|
|
29
30
|
signal: request.signal,
|
|
30
31
|
filename: annieId,
|
|
32
|
+
...(noCache && { cacheControl: "no-store" }),
|
|
31
33
|
});
|
|
32
34
|
}
|
|
@@ -1,18 +1,26 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
1
2
|
import { effieWebUrl } from "@effing/effie";
|
|
2
|
-
import {
|
|
3
|
-
import type {
|
|
3
|
+
import { createCanvas, renderReactElement } from "@effing/canvas";
|
|
4
|
+
import type { FontData } from "@effing/canvas";
|
|
4
5
|
import { serialize } from "@effing/serde";
|
|
5
6
|
|
|
6
|
-
export type { FontData
|
|
7
|
+
export type { FontData } from "@effing/canvas";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
|
-
* Generate a data URL for a PNG image from a React/JSX
|
|
10
|
+
* Generate a data URL for a PNG image from a React/JSX element
|
|
10
11
|
*/
|
|
11
|
-
export async function
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
export async function pngUrlFromReactElement(
|
|
13
|
+
element: ReactNode,
|
|
14
|
+
{
|
|
15
|
+
width,
|
|
16
|
+
height,
|
|
17
|
+
fonts,
|
|
18
|
+
}: { width: number; height: number; fonts: FontData[] },
|
|
14
19
|
) {
|
|
15
|
-
const
|
|
20
|
+
const canvas = createCanvas(width, height);
|
|
21
|
+
const ctx = canvas.getContext("2d");
|
|
22
|
+
await renderReactElement(ctx, element, { fonts });
|
|
23
|
+
const buffer = await canvas.encode("png");
|
|
16
24
|
return effieWebUrl(`data:image/png;base64,${buffer.toString("base64")}`);
|
|
17
25
|
}
|
|
18
26
|
|
package/template/package.json
CHANGED
|
@@ -3,9 +3,7 @@
|
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"scripts": {
|
|
6
|
-
"build": "
|
|
7
|
-
"build:app": "react-router build",
|
|
8
|
-
"build:satori": "vite build -c vite.config.satori.ts",
|
|
6
|
+
"build": "react-router build",
|
|
9
7
|
"dev": "run-p dev:*",
|
|
10
8
|
"dev:app": "react-router dev",
|
|
11
9
|
"dev:ffs": "ffs",
|
|
@@ -13,16 +11,14 @@
|
|
|
13
11
|
"typecheck": "react-router typegen && tsc"
|
|
14
12
|
},
|
|
15
13
|
"dependencies": {
|
|
16
|
-
"@effing/annie": "^0.
|
|
17
|
-
"@effing/annie-player": "^0.
|
|
18
|
-
"@effing/effie": "^0.
|
|
19
|
-
"@effing/effie-preview": "^0.
|
|
20
|
-
"@effing/ffs": "^0.
|
|
21
|
-
"@effing/
|
|
22
|
-
"@
|
|
23
|
-
"@effing/
|
|
24
|
-
"satori": "^0.19.2",
|
|
25
|
-
"@effing/tween": "^0.17.1",
|
|
14
|
+
"@effing/annie": "^0.18.0",
|
|
15
|
+
"@effing/annie-player": "^0.18.0",
|
|
16
|
+
"@effing/effie": "^0.18.0",
|
|
17
|
+
"@effing/effie-preview": "^0.18.0",
|
|
18
|
+
"@effing/ffs": "^0.18.0",
|
|
19
|
+
"@effing/canvas": "^0.18.0",
|
|
20
|
+
"@effing/serde": "^0.18.0",
|
|
21
|
+
"@effing/tween": "^0.18.0",
|
|
26
22
|
"@react-router/node": "^7.0.0",
|
|
27
23
|
"@react-router/serve": "^7.0.0",
|
|
28
24
|
"cross-env": "^7.0.3",
|
package/template/vite.config.ts
CHANGED
|
@@ -6,6 +6,9 @@ export default defineConfig({
|
|
|
6
6
|
server: { port: 3839 }, // 3839 = 0xEFF, how effing cool is that? ʘ‿ʘ
|
|
7
7
|
plugins: [reactRouter(), tsconfigPaths()],
|
|
8
8
|
optimizeDeps: {
|
|
9
|
-
exclude: ["@
|
|
9
|
+
exclude: ["@effing/canvas"],
|
|
10
|
+
},
|
|
11
|
+
ssr: {
|
|
12
|
+
external: ["@effing/canvas"],
|
|
10
13
|
},
|
|
11
14
|
});
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { fileURLToPath } from "node:url";
|
|
2
|
-
import { defineConfig } from "vite";
|
|
3
|
-
|
|
4
|
-
const workerEntry = fileURLToPath(import.meta.resolve("@effing/satori/worker"));
|
|
5
|
-
|
|
6
|
-
// Second Vite build that bundles the satori worker into a single `build/satori.mjs`.
|
|
7
|
-
// Referenced by `app/pool.server.ts` as the worker file in production.
|
|
8
|
-
//
|
|
9
|
-
// Why bundle: The satori pool spawns worker_threads via bare `import()`. Each
|
|
10
|
-
// worker thread independently resolves and parses the full dependency tree on
|
|
11
|
-
// startup (no shared module cache with the main thread). Bundling all pure-JS
|
|
12
|
-
// deps into one file avoids that overhead.
|
|
13
|
-
//
|
|
14
|
-
// Why `@resvg/resvg-js` stays external: It uses a CJS runtime shim to load
|
|
15
|
-
// platform-specific `.node` native binaries — can't be statically bundled.
|
|
16
|
-
//
|
|
17
|
-
// Why `emptyOutDir: false`: The main app build already placed files in `build/`.
|
|
18
|
-
export default defineConfig({
|
|
19
|
-
build: {
|
|
20
|
-
ssr: true,
|
|
21
|
-
outDir: "build",
|
|
22
|
-
rollupOptions: {
|
|
23
|
-
input: workerEntry,
|
|
24
|
-
external: [/\.node$/, "@resvg/resvg-js"],
|
|
25
|
-
output: {
|
|
26
|
-
entryFileNames: "satori.mjs",
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
emptyOutDir: false,
|
|
30
|
-
},
|
|
31
|
-
ssr: {
|
|
32
|
-
noExternal: true,
|
|
33
|
-
},
|
|
34
|
-
});
|