Skip to content

Commit 94260e8

Browse files
committed
core docs should be ready
1 parent 2d8ad16 commit 94260e8

File tree

23 files changed

+497
-80
lines changed

23 files changed

+497
-80
lines changed

apps/astro-docs/astro.config.mjs

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ import { defineConfig } from 'astro/config';
77
// https://astro.build/config
88
export default defineConfig({
99
vite: {
10+
// optimizeDeps: {
11+
// include: ['rxjs', 'rxjs/operators', '@angular/common', '@angular/common/http', '@angular/core/rxjs-interop'],
12+
// },
1013
ssr: {
1114
noExternal: [
15+
// /fesm/,
1216
'angular-three',
1317
'angular-three-soba/**',
1418
'@angular/common',
@@ -51,9 +55,11 @@ export default defineConfig({
5155
},
5256
{
5357
label: 'Core',
58+
collapsed: true,
5459
items: [
5560
{
5661
label: 'Getting Started',
62+
collapsed: true,
5763
items: [
5864
{
5965
label: 'Installation',
@@ -71,6 +77,7 @@ export default defineConfig({
7177
},
7278
{
7379
label: 'API',
80+
collapsed: true,
7481
items: [
7582
{
7683
label: 'NgtCanvas',
@@ -92,26 +99,46 @@ export default defineConfig({
9299
label: 'Raw Value',
93100
slug: 'core/api/raw-value',
94101
},
102+
{
103+
label: 'Store',
104+
slug: 'core/api/store',
105+
},
106+
],
107+
},
108+
{
109+
label: 'Utilities',
110+
collapsed: true,
111+
items: [
112+
{
113+
label: 'injectBeforeRender',
114+
slug: 'core/utilities/before-render',
115+
},
116+
{
117+
label: 'injectLoader',
118+
slug: 'core/utilities/loader',
119+
},
95120
],
96121
},
97-
],
98-
},
99-
{
100-
label: 'Guides',
101-
items: [
102-
// Each item here is one entry in the navigation menu.
103122
{
104-
label: 'Example Guide',
105-
slug: 'guides/example',
123+
label: 'Advanced',
124+
collapsed: true,
125+
items: [
126+
{
127+
label: 'Portals',
128+
slug: 'core/advanced/portals',
129+
},
130+
{
131+
label: 'Routed Scene',
132+
slug: 'core/advanced/routed-scene',
133+
},
134+
{
135+
label: 'Performance',
136+
slug: 'core/advanced/performance',
137+
},
138+
],
106139
},
107140
],
108141
},
109-
{
110-
label: 'Reference',
111-
autogenerate: {
112-
directory: 'reference',
113-
},
114-
},
115142
],
116143
expressiveCode: {
117144
themes: ['dark-plus', 'light-plus'],
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
title: Performance
3+
description: Details about the Angular Three Performance
4+
---
5+
6+
## Reuse Geometries and Materials
7+
8+
Each Geometry and Material consumes the GPU's resources. If we know certain Geometries and/or Materials will repeat, we can reuse them
9+
10+
### Imperative
11+
12+
We can have static geometries and materials as Component's properties
13+
14+
```angular-ts
15+
@Component({
16+
standalone: true,
17+
template: `
18+
<ngt-mesh [geometry]="sphere" [material]="redMaterial" [position]="[1, 1, 1]" />
19+
<ngt-mesh [geometry]="sphere" [material]="redMaterial" [position]="[2, 2, 2]" />
20+
`,
21+
})
22+
export class SceneGraph {
23+
readonly sphere = new THREE.SphereGeometry(1, 32, 32);
24+
readonly redMaterial = new THREE.MeshBasicMaterial({ color: 'red' });
25+
}
26+
````
27+
28+
We can also store these static objects in a Service to reuse across the application or turn them into Signals.
29+
30+
### Declarative
31+
32+
We can put the Geometries and Materials declaratively on the template so they can react to Input changes; and still can reuse them
33+
34+
```angular-html
35+
<ngt-sphere-geometry #sphere *args="[1, 32, 32]" attach="none" />
36+
<ngt-mesh-basic-material #redMaterial color="red" attach="none" />
37+
38+
<ngt-mesh [geometry]="sphere" [material]="redMaterial" [position]="[1, 1, 1]" />
39+
<ngt-mesh [geometry]="sphere" [material]="redMaterial" [position]="[2, 2, 2]" />
40+
```
41+
42+
:::tip[Did you know?]
43+
44+
Setting `attach="none"` on the Material and Geometry components will prevent them from being attached to the parent, which is a `Scene` in this case.
45+
46+
:::
47+
48+
## On-demand Rendering
49+
50+
> Credit: [React Three Fiber](https://docs.pmnd.rs/react-three-fiber/advanced/scaling-performance#on-demand-rendering)
51+
52+
The SceneGraph is usually rendered at 60 frames per second. This makes sense if the SceneGraph contains constantly moving parts (eg: game). Consequently, this drains the device's resources.
53+
54+
If the SceneGraph has static entities, or entities that are allowed to come to a rest, constantly rendering at 60fps would be wasteful. In those cases, we can opt into on-demand rendering, which will only render when necessary. All we have to do is to set `frameloop="demand"` on the `<ngt-canvas>`
55+
56+
```angular-html
57+
<ngt-canvas [sceneGraph]="SceneGraph" frameloop="demand" />
58+
```
59+
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
---
2+
title: Portals
3+
description: Details about the Angular Three `NgtPortal`
4+
---
5+
6+
In THREE.js, there is a construct called `WebGLRenderTarget`. It is used to render the scene into a texture and then
7+
render the texture into the canvas. This is useful for things like post-processing effects, or HUD-like visuals.
8+
9+
:::tip[Did you know?]
10+
11+
Recommended read: [Beautiful and Mind-bending Effects with WebGLRenderTarget](https://blog.maximeheckel.com/posts/beautiful-and-mind-bending-effects-with-webgl-render-targets/)
12+
13+
:::
14+
15+
In Angular Three, we can use `NgtPortal` component to create an off-screen buffer that can be used to render secondary scenes.
16+
17+
`NgtPortal` provides a _layered_ `NgtSignalStore<NgtState>` that its children can inject. This makes sure that children of `NgtPortal`
18+
access the state of the `NgtPortal` and not the root `NgtSignalStore<NgtState>`.
19+
20+
```angular-ts
21+
@Component({
22+
template: `
23+
<ngt-mesh>
24+
<ngt-torus-geometry />
25+
</ngt-mesh>
26+
27+
<ngt-portal [container]="secondaryScene">
28+
<ng-template portalContent>
29+
<ngts-perspective-camera [options]="{ makeDefault: true }" />
30+
<ngt-mesh>
31+
<ngt-box-geometry />
32+
</ngt-mesh>
33+
</ng-template>
34+
</ngt-portal>
35+
`,
36+
imports: [NgtPortal, NgtPortalContent],
37+
})
38+
export class HUD {
39+
secondaryScene = new Scene();
40+
}
41+
```
42+
43+
The portal can have its own scene, camera, and children.
44+
45+
:::note
46+
47+
The `NgtsPerspectiveCamera` in the example above is an abstraction
48+
over `THREE.PerspectiveCamera` that has the ability to make itself the default camera for the closest `NgtSignalStore<NgtState>`.
49+
50+
:::
51+
52+
## Examples
53+
54+
TBD
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
---
2+
title: Routed Scene
3+
description: Details about the Angular Three `NgtRoutedScene`
4+
---
5+
6+
import { Tabs, TabItem } from '@astrojs/starlight/components';
7+
8+
Angular Three supports routed scenes. This is useful for when you want to have different scene graphs for different routes but keep the
9+
root `NgtCanvas` component the same.
10+
11+
To enable routed scenes, pass `'routed'` to the `sceneGraph` input of the `NgtCanvas` component.
12+
13+
```angular-html
14+
<ngt-canvas sceneGraph="routed" />
15+
```
16+
17+
## Example
18+
19+
To start, we can create two Scene components: `RedScene` and `BlueScene`
20+
21+
<Tabs>
22+
<TabItem label="src/app/red-scene.component.ts">
23+
```angular-ts
24+
import { Component, viewChild, ChangeDetectionStrategy, CUSTOM_ELEMENTS_SCHEMA, ElementRef } from '@angular/core';
25+
import { injectBeforeRender } from 'angular-three';
26+
27+
@Component({
28+
standalone: true,
29+
template: `
30+
<ngt-mesh #cube>
31+
<ngt-box-geometry />
32+
<ngt-mesh-basic-material color="red" />
33+
</ngt-mesh>
34+
`,
35+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
36+
changeDetection: ChangeDetectionStrategy.OnPush,
37+
})
38+
export default class RedScene {
39+
cubeRef = viewChild.required<ElementRef<THREE.Mesh>>('cube');
40+
41+
constructor() {
42+
injectBeforeRender(({ clock }) => {
43+
this.cube().nativeElement.rotation.x = clock.elapsedTime;
44+
this.cube().nativeElement.rotation.y = clock.elapsedTime;
45+
});
46+
}
47+
}
48+
```
49+
</TabItem>
50+
51+
<TabItem label="src/app/blue-scene.component.ts">
52+
```angular-ts
53+
import { Component, viewChild, ChangeDetectionStrategy, CUSTOM_ELEMENTS_SCHEMA, ElementRef } from '@angular/core';
54+
import { injectBeforeRender } from 'angular-three';
55+
56+
@Component({
57+
standalone: true,
58+
template: `
59+
<ngt-mesh #cube>
60+
<ngt-box-geometry />
61+
<ngt-mesh-basic-material color="blue" />
62+
</ngt-mesh>
63+
`,
64+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
65+
changeDetection: ChangeDetectionStrategy.OnPush,
66+
})
67+
export default class BlueScene {
68+
cubeRef = viewChild.required<ElementRef<THREE.Mesh>>('cube');
69+
70+
constructor() {
71+
injectBeforeRender(({ clock }) => {
72+
this.cube().nativeElement.rotation.x = clock.elapsedTime;
73+
this.cube().nativeElement.rotation.y = clock.elapsedTime;
74+
});
75+
}
76+
}
77+
```
78+
</TabItem>
79+
</Tabs>
80+
81+
Next, we'll use `RedScene` and `BlueScene` in our routing configuration.
82+
83+
```ts
84+
import { bootstrapApplication } from '@angular/platform-browser';
85+
import { provideRouter } from '@angular/router';
86+
import { AppComponent } from './app/app.component';
87+
88+
bootstrapApplication(AppComponent, {
89+
providers: [
90+
provideRouter([
91+
{
92+
path: '',
93+
loadComponent: () => import('./app/red-scene.component'),
94+
},
95+
{
96+
path: 'blue',
97+
loadComponent: () => import('./app/blue-scene.component'),
98+
},
99+
]),
100+
],
101+
}).catch((err) => console.error(err));
102+
```

apps/astro-docs/src/content/docs/core/api/custom-renderer.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,8 @@ The events system in NGT is completely ported from R3F. For more information, pl
313313
This is **discouraged** at the moment due to how Angular Zoneless Change Detection works.
314314
`(beforeRender)` handler will trigger change detection on every frame if used with `provideExperimentalZonelessChangeDetection()`.
315315

316+
In the meantime, [`injectBeforeRender`](/core/utilities/before-render) is a better alternative.
317+
316318
:::
317319

318320
To register a callback in the animation loop, listen to the `beforeRender` event on a NGT element.

0 commit comments

Comments
 (0)