Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(daguerreo): 🎉 Set up Daguerreo #338

Draft
wants to merge 20 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
cc5de57
chore(daguerreo): :construction: Set up first version of Daguerreo
Joery-M Nov 24, 2024
ce42739
refactor(daguerreo): :construction: Removed streams for simplicity
Joery-M Nov 24, 2024
4fe39e7
chore(daguerreo): :memo: Added daguerreo to packages
Joery-M Nov 24, 2024
8fa8439
feat(daguerreo): :sparkles: Implemented transforms
Joery-M Nov 26, 2024
1dd0241
Merge remote-tracking branch 'origin/main' into 33-daguerreo-package-…
Joery-M Nov 26, 2024
f06d79f
Merge remote-tracking branch 'origin/main' into 33-daguerreo-package-…
Joery-M Nov 30, 2024
b6ef23a
chore(general): :art: Format
Joery-M Nov 30, 2024
ab9227e
feat(daguerreo): :sparkles: Added load hook. Added pause and frame co…
Joery-M Nov 30, 2024
5fa97b2
feat(daguerreo): :sparkles: Added animateable properties
Joery-M Nov 30, 2024
876126d
refactor(daguerreo): :recycle: Moved interpolation function to be per…
Joery-M Dec 3, 2024
46d6f82
Merge remote-tracking branch 'origin/main' into 33-daguerreo-package-…
Joery-M Dec 9, 2024
34b9ee1
Merge remote-tracking branch 'origin/main' into 33-daguerreo-package-…
Joery-M Dec 9, 2024
13b6954
Merge branch '33-daguerreo-package-setup' of https://github.com/Joery…
Joery-M Dec 9, 2024
ef7cadb
refactor(daguerreo): :recycle: Removed keyframes from dg
Joery-M Dec 9, 2024
7f3dcd8
refactor(daguerreo): :recycle: Refactored effect properties
Joery-M Dec 13, 2024
b569701
fix(daguerreo): :bug: Made rotation wrap around 360
Joery-M Dec 13, 2024
5ac9b9d
Merge remote-tracking branch 'origin/main' into 33-daguerreo-package-…
Joery-M Dec 14, 2024
cd3767c
feat(daguerreo): :sparkles: Added quality setting
Joery-M Dec 14, 2024
8281acb
perf(daguerreo): :zap: Made some temporary optimizations
Joery-M Dec 14, 2024
97ebb3f
chore(daguerreo): :pushpin: Made vue a peer dep of daguerreo
Joery-M Dec 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/renovate.json5
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@

// Pinned
'@vue/devtools-api',
"typescript" // https://github.com/vuejs/language-tools/issues/5018
'typescript' // https://github.com/vuejs/language-tools/issues/5018
]
}
32 changes: 32 additions & 0 deletions packages/daguerreo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "@safelight/daguerreo",
"version": "1.0.0",
"author": "Joery Münninghoff",
"repository": {
"type": "git",
"url": "https://github.com/Joery-M/Safelight"
},
"contributors": [],
"license": "MIT",
"type": "module",
"exports": {
".": {
"import": "./src/index.ts"
},
"./sources/*": {
"import": "./src/sources/*.ts"
},
"./transformers/*": {
"import": "./src/transformers/*.ts"
}
},
"devDependencies": {
"type-fest": "^4.30.1"
},
"dependencies": {
"gifuct-js": "^2.1.2"
},
"peerDependencies": {
"vue": "^3.5.13"
}
}
Binary file added packages/daguerreo/src/assets/cat.avif
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
164 changes: 164 additions & 0 deletions packages/daguerreo/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import { computed, shallowReactive, shallowRef } from 'vue';
import type { DGTransformProperties, DGTransformProperty } from './properties';
import type { DaguerreoSourceEffect, DaguerreoSourcePayload } from './sourceEffect';
import type { DaguerreoTransformEffect, DaguerreoTransformPayload } from './transformEffect';

export class Daguerreo {
private source = shallowRef<DaguerreoSourceEffect | undefined>(undefined);
readonly effects = shallowReactive<DaguerreoTransformEffect[]>([]);
private effectsWithSourceInitHooks = computed(() =>
this.effects.filter((e) => !!e.sourceInitialized)
);
private effectsWithTransformHooks = computed(() => this.effects.filter((e) => !!e.transform));
private ranLoadFunction = false;

addEffect(effect: DaguerreoTransformEffect) {
this.effects.push(effect);
}
removeEffect(effect: DaguerreoTransformEffect) {
this.effects.slice(this.effects.indexOf(effect) - 1, 1);
}
setSource(source: DaguerreoSourceEffect) {
this.source.value = source;
this.ranLoadFunction = false;
}

reset() {
this.source.value = undefined;
this.ranLoadFunction = false;
this.effects.splice(0, this.effects.length);
}

getTransformProps() {
const allProps: DGTransformProperties[] = [];
for (let i = 0; i < this.effects.length; i++) {
const effect = this.effects[i];

const props: DGTransformProperties = {};
if (effect.properties) {
for (const key in effect.properties) {
if (key in effect.properties) {
const prop = effect.properties[key] as DGTransformProperty;
props[key] = prop.value();
}
}
}

allProps[i] = props;
}

return allProps;
}

async process(
config: DaguerreoSourcePayload,
transformProps: DGTransformProperties[] = this.getTransformProps()
): Promise<DaguerreoResult> {
const effectBase = this.source.value;
if (!effectBase) throw new Error('No source effect defined');

if (!this.ranLoadFunction) {
this.ranLoadFunction = true;
await effectBase.load?.();
}

const payload: DaguerreoTransformPayload = Object.assign(
// Default values
{
matrix: new DOMMatrix(),
compositeOperation: 'source-over',
opacity: 1,
frame: config.frame,
frameDuration: config.frameDuration,
width: config.width,
height: config.height,
maxWidth: config.width,
maxHeight: config.height,
quality: config.quality
},
await effectBase.source(config)
);

switch (config.quality) {
case 'preview':
payload.ctx.imageSmoothingQuality = 'medium';
break;
case 'rough':
payload.ctx.imageSmoothingQuality = 'low';
break;

default:
payload.ctx.imageSmoothingQuality = 'high';
break;
}

// Run initialize methods
const initFunctions = this.effectsWithSourceInitHooks.value.map((e) =>
e.sourceInitialized?.({ height: payload.height, width: payload.width })
);
await Promise.allSettled(initFunctions);

// Run effects
for (let i = 0; i < this.effectsWithTransformHooks.value.length; i++) {
const effect = this.effectsWithTransformHooks.value[i];

const props: DGTransformProperties = transformProps[i] ?? {};
if (effect.properties) {
for (const key in effect.properties) {
if (key in effect.properties && !(key in props)) {
const prop = effect.properties[key];
props[key] = prop.value();
}
}
}
const result = await effect.transform!({ ...payload, properties: props });
// Assign props
if (result) Object.assign(payload, result);
}

return {
width: payload.width,
height: payload.height,
frameDuration: config.frameDuration,
image: payload.ctx.canvas.transferToImageBitmap(),
matrix: payload.matrix,
opacity: payload.opacity,
compositeOperation: payload.compositeOperation
} as DaguerreoResult;
}
}

export type QualitySetting = 'rough' | 'preview' | 'final';

export type DaguerreoEffect = DaguerreoSourceEffect | DaguerreoTransformEffect;

export interface DaguerreoResult {
/**
* Current frame width
*/
width: number;
/**
* Current frame height
*/
height: number;
/**
* Current frame duration
*/
frameDuration: number;

image: ImageBitmap;

matrix: DOMMatrix;
/**
* Number ranging from 0-1 that defines the opacity used for compositing
*/
opacity: number;
/**
* The blend mode used for compositing
*/
compositeOperation: GlobalCompositeOperation;
}

export * from './properties';
export * from './sourceEffect';
export * from './transformEffect';
58 changes: 58 additions & 0 deletions packages/daguerreo/src/properties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type { PartialDeep } from 'type-fest';
import { ref } from 'vue';

export function dgNumberProperty(
value: number,
meta?: PartialDeep<NumberPropertyConfig>
): DGTransformProperty<number, PartialDeep<NumberPropertyConfig>> {
const curValue = ref(value);
return {
type: 'number',
value() {
return curValue.value;
},
displayValue() {
return meta?.transform?.toDisplay
? meta.transform.toDisplay(curValue.value)
: curValue.value;
},
setValue(value: number) {
curValue.value = meta?.transform?.toValue ? meta.transform.toValue(value) : value;
},
meta
};
}

export interface NumberPropertyConfig {
min: number;
max: number;
step: number;
slider: boolean;
/**
* @default false
*/
integerOnly: boolean;
transform: {
toDisplay: (value: number) => number;
toValue: (display: number) => number;
};
}

export type DGPropertyTypes = 'number';

export type DGTransformProperty<T = any, Meta = Record<string, any>> = {
type: DGPropertyTypes;
value(): T;
displayValue(): T;
setValue(v: T): void;
meta?: Meta;
};

export interface DGTransformProperties {
[key: string]: DGTransformProperty;
}
export type DGComputedProperties<P extends DGTransformProperties | undefined> = P extends undefined
? undefined
: {
[K in keyof P]: ReturnType<NonNullable<P>[K]['value']>;
};
41 changes: 41 additions & 0 deletions packages/daguerreo/src/sourceEffect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { Promisable, SetRequired } from 'type-fest';
import type { DaguerreoTransformPayload } from './transformEffect';
import type { QualitySetting } from '.';

export interface DaguerreoSourceEffect {
name: string;
load?: () => Promisable<void>;
source: (config: DaguerreoSourcePayload) => Promisable<DaguerreoSourceResult>;
}

export type DaguerreoSourceResult = SetRequired<Partial<DaguerreoTransformPayload>, 'ctx'>;

export interface DaguerreoSourcePayload {
/**
* Current frame number
*/
frame: number;
/**
* Frame duration in milliseconds.
*/
frameDuration: number;
/**
* Timeline width
*/
width: number;
/**
* Timeline height
*/
height: number;
/**
* The desired rendering quality.
*
* For if your source effect is able to render with different
* performance characteristics.
*/
quality: QualitySetting;
}

export function defineSource(def: DaguerreoSourceEffect) {
return def;
}
Loading
Loading