Skip to content

Commit 5a3a419

Browse files
committed
sparkles
1 parent 2884002 commit 5a3a419

File tree

12 files changed

+384
-7
lines changed

12 files changed

+384
-7
lines changed

libs/core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export * from './lib/before-render';
22
export * from './lib/canvas';
33
export * from './lib/directives/args';
4+
export * from './lib/directives/key';
45
export * from './lib/directives/parent';
56
export * from './lib/directives/repeat';
67
export { type NgtCamera } from './lib/events';

libs/core/src/lib/directives/args.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Directive, Input } from '@angular/core';
22
import { NgtCommonDirective } from './common';
33

4-
@Directive({ selector: '[args]', standalone: true })
4+
@Directive({ selector: 'ng-template[args]', standalone: true })
55
export class NgtArgs<TArgs extends any[] = any[]> extends NgtCommonDirective {
66
private injectedArgs: TArgs = [] as unknown as TArgs;
77

libs/core/src/lib/directives/common.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import { Directive, NgZone, TemplateRef, ViewContainerRef, inject, type EmbeddedViewRef } from '@angular/core';
1+
import {
2+
DestroyRef,
3+
Directive,
4+
NgZone,
5+
TemplateRef,
6+
ViewContainerRef,
7+
inject,
8+
type EmbeddedViewRef,
9+
} from '@angular/core';
210
import { SPECIAL_INTERNAL_ADD_COMMENT } from '../renderer/constants';
311
import { safeDetectChanges } from '../utils/safe-detect-changes';
412

@@ -18,6 +26,10 @@ export abstract class NgtCommonDirective {
1826
commentNode[SPECIAL_INTERNAL_ADD_COMMENT]();
1927
delete commentNode[SPECIAL_INTERNAL_ADD_COMMENT];
2028
}
29+
30+
inject(DestroyRef).onDestroy(() => {
31+
this.view?.destroy();
32+
});
2133
}
2234

2335
abstract validate(): boolean;

libs/core/src/lib/directives/key.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import {
2+
DestroyRef,
3+
Directive,
4+
Input,
5+
NgZone,
6+
TemplateRef,
7+
ViewContainerRef,
8+
inject,
9+
type EmbeddedViewRef,
10+
} from '@angular/core';
11+
import { safeDetectChanges } from '../utils/safe-detect-changes';
12+
13+
@Directive({ selector: 'ng-template[key]', standalone: true })
14+
export class NgtKey {
15+
private vcr = inject(ViewContainerRef);
16+
private templateRef = inject(TemplateRef);
17+
private zone = inject(NgZone);
18+
19+
private lastKey = '';
20+
private viewRef?: EmbeddedViewRef<unknown>;
21+
22+
@Input() set key(key: string) {
23+
if (this.lastKey !== key) {
24+
this.createView();
25+
this.lastKey = key;
26+
}
27+
}
28+
29+
constructor() {
30+
inject(DestroyRef).onDestroy(() => {
31+
this.viewRef?.destroy();
32+
});
33+
}
34+
35+
private createView() {
36+
if (!this.viewRef?.destroyed) {
37+
this.viewRef?.destroy();
38+
}
39+
40+
this.zone.runOutsideAngular(() => {
41+
this.viewRef = this.vcr.createEmbeddedView(this.templateRef);
42+
safeDetectChanges(this.viewRef);
43+
});
44+
}
45+
}

libs/core/src/lib/directives/parent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Directive, Input } from '@angular/core';
22
import type { NgtInjectedRef } from '../ref';
33
import { NgtCommonDirective } from './common';
44

5-
@Directive({ selector: '[parent]', standalone: true })
5+
@Directive({ selector: 'ng-template[parent]', standalone: true })
66
export class NgtParent extends NgtCommonDirective {
77
private injectedParent: string | THREE.Object3D | NgtInjectedRef<THREE.Object3D> = null!;
88

libs/soba/abstractions/src/grid/grid.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { CUSTOM_ELEMENTS_SCHEMA, Component, Input } from '@angular/core';
22
import { NgtArgs, extend, injectBeforeRender, injectNgtRef, signalStore, type NgtMesh } from 'angular-three';
3-
import { GridMaterial, type NgtsGridMaterialState } from 'angular-three-soba/shaders';
3+
import { GridMaterial, type NgtGridMaterialState } from 'angular-three-soba/shaders';
44
import * as THREE from 'three';
55
import { Mesh, PlaneGeometry } from 'three';
66

@@ -9,7 +9,7 @@ extend({ GridMaterial, Mesh, PlaneGeometry });
99
export type NgtsGridState = {
1010
/** Default plane-geometry arguments */
1111
args?: ConstructorParameters<typeof THREE.PlaneGeometry>;
12-
} & NgtsGridMaterialState;
12+
} & NgtGridMaterialState;
1313

1414
declare global {
1515
interface HTMLElementTagNameMap {

libs/soba/shaders/src/grid-material/grid-material.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export const GridMaterial = shaderMaterial(
7979
`,
8080
);
8181

82-
export type NgtsGridMaterialState = {
82+
export type NgtGridMaterialState = {
8383
/** Cell size, default: 0.5 */
8484
cellSize?: number;
8585
/** Cell thickness, default: 0.5 */
@@ -109,6 +109,6 @@ declare global {
109109
/**
110110
* @extends ngt-shader-material
111111
*/
112-
'ngt-grid-material': NgtsGridMaterialState & NgtShaderMaterial;
112+
'ngt-grid-material': NgtGridMaterialState & NgtShaderMaterial;
113113
}
114114
}

libs/soba/shaders/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './grid-material/grid-material';
22
export * from './shader-material/shader-material';
3+
export * from './sparkles-material/sparkles-material';
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import type { NgtShaderMaterial } from 'angular-three';
2+
import * as THREE from 'three';
3+
import { shaderMaterial } from '../shader-material/shader-material';
4+
5+
export const SparklesMaterial = shaderMaterial(
6+
{ time: 0, pixelRatio: 1 },
7+
` uniform float pixelRatio;
8+
uniform float time;
9+
attribute float size;
10+
attribute float speed;
11+
attribute float opacity;
12+
attribute vec3 noise;
13+
attribute vec3 color;
14+
varying vec3 vColor;
15+
varying float vOpacity;
16+
void main() {
17+
vec4 modelPosition = modelMatrix * vec4(position, 1.0);
18+
modelPosition.y += sin(time * speed + modelPosition.x * noise.x * 100.0) * 0.2;
19+
modelPosition.z += cos(time * speed + modelPosition.x * noise.y * 100.0) * 0.2;
20+
modelPosition.x += cos(time * speed + modelPosition.x * noise.z * 100.0) * 0.2;
21+
vec4 viewPosition = viewMatrix * modelPosition;
22+
vec4 projectionPostion = projectionMatrix * viewPosition;
23+
gl_Position = projectionPostion;
24+
gl_PointSize = size * 25. * pixelRatio;
25+
gl_PointSize *= (1.0 / - viewPosition.z);
26+
vColor = color;
27+
vOpacity = opacity;
28+
}`,
29+
` varying vec3 vColor;
30+
varying float vOpacity;
31+
void main() {
32+
float distanceToCenter = distance(gl_PointCoord, vec2(0.5));
33+
float strength = 0.05 / distanceToCenter - 0.1;
34+
gl_FragColor = vec4(vColor, strength * vOpacity);
35+
#include <tonemapping_fragment>
36+
#include <${parseInt(THREE.REVISION.replace(/\D+/g, '')) >= 154 ? 'colorspace_fragment' : 'encodings_fragment'}>
37+
}`,
38+
);
39+
40+
export type NgtSparklesMaterialState = {
41+
time?: number;
42+
pixelRatio?: number;
43+
};
44+
45+
declare global {
46+
interface HTMLElementTagNameMap {
47+
/**
48+
* @extends ngt-shader-material
49+
*/
50+
'ngt-sparkles-material': NgtSparklesMaterialState & NgtShaderMaterial;
51+
}
52+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { CUSTOM_ELEMENTS_SCHEMA, Component, Input, computed, signal } from '@angular/core';
2+
import { NgtsPerspectiveCamera } from 'angular-three-soba/cameras';
3+
import { NgtsOrbitControls } from 'angular-three-soba/controls';
4+
import { NgtsSparkles } from 'angular-three-soba/staging';
5+
import { makeDecorators, makeStoryObject, number } from '../setup-canvas';
6+
7+
@Component({
8+
standalone: true,
9+
template: `
10+
<ngts-sparkles
11+
color="orange"
12+
[size]="sizes()"
13+
[count]="_amount()"
14+
[opacity]="opacity"
15+
[speed]="speed"
16+
[noise]="noise"
17+
/>
18+
<ngts-orbit-controls />
19+
<ngt-axes-helper />
20+
<ngts-perspective-camera [position]="[2, 2, 2]" [makeDefault]="true" />
21+
`,
22+
imports: [NgtsSparkles, NgtsOrbitControls, NgtsPerspectiveCamera],
23+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
24+
})
25+
class DefaultSparklesStory {
26+
@Input() opacity = 1;
27+
@Input() speed = 0.3;
28+
@Input() noise = 1;
29+
30+
private _random = signal(true);
31+
@Input() set random(random: boolean) {
32+
this._random.set(random);
33+
}
34+
35+
private _size = signal(5);
36+
@Input() set size(size: number) {
37+
this._size.set(size);
38+
}
39+
40+
_amount = signal(100);
41+
@Input() set amount(amount: number) {
42+
this._amount.set(amount);
43+
}
44+
45+
sizes = computed(() => {
46+
if (this._random())
47+
return new Float32Array(Array.from({ length: this._amount() }, () => Math.random() * this._size()));
48+
return this._size();
49+
});
50+
}
51+
52+
export default {
53+
title: 'Staging/Sparkles',
54+
decorators: makeDecorators(),
55+
};
56+
export const Default = makeStoryObject(DefaultSparklesStory, {
57+
canvasOptions: { camera: { position: [1, 1, 1] }, controls: false },
58+
argsOptions: {
59+
random: true,
60+
amount: number(100, { range: true, max: 500, step: 1 }),
61+
size: number(5, { range: true, min: 0, max: 10, step: 1 }),
62+
noise: number(1, { range: true, min: 0, max: 1, step: 0.01 }),
63+
speed: number(0.3, { range: true, min: 0, max: 20, step: 0.1 }),
64+
opacity: number(1, { range: true, min: 0, max: 1, step: 0.01 }),
65+
},
66+
});

0 commit comments

Comments
 (0)