diff --git a/src/features/particles/Particles.vue b/src/features/particles/Particles.vue
index 57feb7e..afe40be 100644
--- a/src/features/particles/Particles.vue
+++ b/src/features/particles/Particles.vue
@@ -1,11 +1,19 @@
+onMounted,
+
+
+
diff --git a/src/features/particles/particles.tsx b/src/features/particles/particles.tsx
index 010bb36..4f460a9 100644
--- a/src/features/particles/particles.tsx
+++ b/src/features/particles/particles.tsx
@@ -1,39 +1,101 @@
-import ParticlesComponent from "./Particles.vue";
+import ParticlesComponent from "features/particles/Particles.vue";
+import { Container } from "tsparticles-engine";
import { IEmitter } from "tsparticles-plugin-emitters/Options/Interfaces/IEmitter";
import { EmitterInstance } from "tsparticles-plugin-emitters/EmitterInstance";
import { EmitterContainer } from "tsparticles-plugin-emitters/EmitterContainer";
import { Ref, shallowRef } from "vue";
-import { registerGameComponent } from "game/settings";
-import { jsx } from "features/feature";
+import { Component, GatherProps, getUniqueID, Replace, setDefault } from "features/feature";
+import { createLazyProxy } from "util/proxies";
-registerGameComponent(jsx(() => ));
+export const ParticlesType = Symbol("Particles");
-const containerRef: Ref = shallowRef(null);
+export interface ParticlesOptions {
+ fullscreen?: boolean;
+ zIndex?: number;
+ onContainerResized?: (boundingRect: DOMRect) => void;
+}
-let emittersToAdd: {
- resolve: (value: EmitterInstance | PromiseLike) => void;
- options: IEmitter & { particles: Required["particles"] };
-}[] = [];
+export interface BaseParticles {
+ id: string;
+ containerRef: Ref;
+ addEmitter: (
+ options: IEmitter & { particles: Required["particles"] }
+ ) => Promise;
+ removeEmitter: (emitter: EmitterInstance) => void;
+ type: typeof ParticlesType;
+ [Component]: typeof ParticlesComponent;
+ [GatherProps]: () => Record;
+}
-export function addEmitter(
- options: IEmitter & { particles: Required["particles"] }
-): Promise {
- if (containerRef.value) {
- // TODO why does addEmitter require a position parameter
- return Promise.resolve(containerRef.value.addEmitter(options));
+export type Particles = Replace<
+ T & BaseParticles,
+ {
+ fullscreen: undefined extends T["fullscreen"] ? true : T["fullscreen"];
+ zIndex: undefined extends T["zIndex"] ? 1 : T["zIndex"];
}
- return new Promise(resolve => {
- emittersToAdd.push({ resolve, options });
+>;
+
+export type GenericParticles = Replace<
+ Particles,
+ {
+ fullscreen: boolean;
+ zIndex: number;
+ }
+>;
+
+export function createParticles(
+ optionsFunc: () => T & ThisType>
+): Particles {
+ return createLazyProxy(() => {
+ const particles: T & Partial = optionsFunc();
+ particles.id = getUniqueID("particles-");
+ particles.type = ParticlesType;
+ particles[Component] = ParticlesComponent;
+
+ particles.containerRef = shallowRef(null);
+ particles.addEmitter = (
+ options: IEmitter & { particles: Required["particles"] }
+ ): Promise => {
+ const genericParticles = particles as GenericParticles;
+ if (genericParticles.containerRef.value) {
+ // TODO why does addEmitter require a position parameter
+ return Promise.resolve(genericParticles.containerRef.value.addEmitter(options));
+ }
+ return new Promise(resolve => {
+ emittersToAdd.push({ resolve, options });
+ });
+ };
+ particles.removeEmitter = (emitter: EmitterInstance) => {
+ // TODO I can't find a proper way to remove an emitter without accessing private functions
+ emitter.emitters.removeEmitter(emitter);
+ };
+
+ let emittersToAdd: {
+ resolve: (value: EmitterInstance | PromiseLike) => void;
+ options: IEmitter & { particles: Required["particles"] };
+ }[] = [];
+
+ function onInit(container: EmitterContainer & Container) {
+ (particles as GenericParticles).containerRef.value = container;
+ emittersToAdd.forEach(({ resolve, options }) => resolve(container.addEmitter(options)));
+ emittersToAdd = [];
+ }
+
+ setDefault(particles, "fullscreen", true);
+ setDefault(particles, "zIndex", 1);
+ particles.onContainerResized = particles.onContainerResized?.bind(particles);
+
+ particles[GatherProps] = function (this: GenericParticles) {
+ const { id, fullscreen, zIndex, onContainerResized } = this;
+ return {
+ id,
+ fullscreen,
+ zIndex,
+ onContainerResized,
+ onInit
+ };
+ };
+
+ return particles as unknown as Particles;
});
}
-
-export function removeEmitter(emitter: EmitterInstance) {
- // TODO I can't find a proper way to remove an emitter without accessing private functions
- emitter.emitters.removeEmitter(emitter);
-}
-
-function onInit(container: EmitterContainer) {
- containerRef.value = container;
- emittersToAdd.forEach(({ resolve, options }) => resolve(container.addEmitter(options)));
- emittersToAdd = [];
-}