fragment
fragment copied to clipboard
feat: add TypeScript support
Summary
This PR adds TypeScript support for Fragment sketches.
Since Fragment uses Vite behind the scenes (which already supports TypeScript transpilation via esbuild), TypeScript support is pretty straightforward to add.
Result
- The CLI now accepts sketch files with a
.ts
extension, for example:fragment ./sketch.ts --new
. - Templates are available in TypeScript version, you just need to add
-ts
at the end of the template name:fragment ./sketch.ts --new --template=2d-ts
. -
tsconfig.json
file is created automatically for you with the right paths when you create a new sketch based on a TypeScript template. - All sketch exports are typed and can be imported from
@fragment/types
. You just need to pass your current sketchrendering
as a generic to lifecycle functions to have the proper types, for example:Init<"2d">
. - Props are also typed thanks to a helper function
typedProps
. - TypeScript modules have been added for GLSL files (
.glsl
,.vs
,.fs
,.vert
, and.frag
).
Demo
https://user-images.githubusercontent.com/662153/188423546-4e600187-cb86-4e42-a3d4-e796f9b8d76b.mov
Code sample
import { onControlChange } from "@fragment/triggers";
import { typedProps } from "@fragment/types/helpers";
import type {
Init,
Update,
Resize,
FilenamePattern,
Name,
Fps,
Duration,
Rendering,
} from "@fragment/types";
export let props = typedProps({
number: {
value: 50,
hidden: false,
onChange({ value }) {
console.log(value);
},
params: {
min: 0,
max: 100,
step: 0.1,
},
},
});
export let init: Init<"2d"> = ({ context, width, height }) => {
onControlChange(18, (event) => {
props.number.value = event.value * 100;
});
};
export let update: Update<"2d"> = ({ canvas, context, width, height }) => {
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.arc(width * 0.5, height * 0.5, props.number.value, 0, Math.PI * 2);
context.fillStyle = "red";
context.fill();
};
export let resize: Resize<"2d"> = ({ context, canvas, width, height }) => {
context.clearRect(0, 0, canvas.width, canvas.height);
};
export let rendering: Rendering = "2d";
export let duration: Duration = 1;
export let fps: Fps = 60;
export let name: Name = "test";
export let filenamePattern: FilenamePattern = ({ filename, suffix }) =>
`${filename}.${suffix}`;
Thanks for this detailed PR @FabienMotte!
There's a few changes I'd like to request and I also have a few questions since I have very little experience with Typescript:
-
In the CLI docs, I find it a bit confusing to have both example with and without typescript following each other. I'd rather have two
<code>
block, the first one left untouched and a second one with just a subtitle With typescript. It seems to me that beginners could misunderstand the command to type if you have no knowledge of what typescript is. If that's the case, you can just ignore the second block and focus on the first command. -
Are
type Duration
,type Fps
andtype Name
really needed ? I find it a bit confusing not to have justnumber
orstring
in the templates. These are primitive data types, I'm wondering what the need for a additional layer here ? -
Looking at package.json, I see that
three
andp5
are hosting their@types
outside of the repository. Could it be done easily ? What's the pros and cons of that ?
And thanks for spotting the filename pattern issue in the docs where suffix
was renamed timestamp
, the docs were indeed not up to date!
I merged some changes into dev
which makes some types obsolete already, sorry 😄
- "vec2" and "vec3" do not exist anymore, in favor of a generic
vec
fieldType. It also supports 4 dimensions vectors now, see #19 for details - ColorInput supports new kinds of values for
hsl
and also objects withr
,g
,b
and optionnallya
keys. See #20 for details
I also noticed that options
seems to be missing in params
types as I get an error when trying to create a select GUI by passing options
to params
.

- In the CLI docs, I find it a bit confusing to have both example with and without typescript following each other. I'd rather have two
<code>
block, the first one left untouched and a second one with just a subtitle With typescript. It seems to me that beginners could misunderstand the command to type if you have no knowledge of what typescript is. If that's the case, you can just ignore the second block and focus on the first command.
I updated the docs to make the separation clearer between JS and TS. Don't hesitate to put yourself as a reviewer and ask for a change if that's not what you had in mind.
- Are
type Duration
,type Fps
andtype Name
really needed ? I find it a bit confusing not to have justnumber
orstring
in the templates. These are primitive data types, I'm wondering what the need for a additional layer here ?
I removed those types, indeed, they are unnecessary.
- Looking at package.json, I see that
three
andp5
are hosting their@types
outside of the repository. Could it be done easily ? What's the pros and cons of that ?
I guess the answer is yes and would make more sense since Fragment is a JavaScript library. The typing should live on https://github.com/DefinitelyTyped/DefinitelyTyped as Three.js or p5.js are doing. I never published a package on this repo, so I would need to see how this can be done.
I merged some changes into
dev
which makes some types obsolete already, sorry 😄
No worries, I'll update those accordingly.
I also noticed that
options
seems to be missing inparams
types as I get an error when trying to create a select GUI by passingoptions
toparams
.
Oops, good catch, totally forgot to include this type in the Prop
union!
Thank you for your comments!