minecraft-renderer 0.1.47 → 0.1.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minecraft-renderer",
3
- "version": "0.1.47",
3
+ "version": "0.1.48",
4
4
  "description": "The most Modular Minecraft world renderer with Three.js WebGL backend",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -170,6 +170,7 @@ export function applyRendererOptions(
170
170
  cfg.shadingTheme = o.vanillaLook ? 'vanilla' : 'high-contrast'
171
171
  cfg.starfield = o.starfieldRendering
172
172
  cfg.defaultSkybox = o.defaultSkybox
173
+ cfg.fov = o.fov
173
174
  }
174
175
 
175
176
  /** World-view + hand/camera options (call when WorldView is ready). */
@@ -47,6 +47,8 @@ export const getInitialPlayerState = () => proxy({
47
47
  heldItemOff: undefined as HandItemBlock | undefined,
48
48
  perspective: 'first_person' as CameraPerspective,
49
49
  onFire: false,
50
+ /** Gameplay FOV scale (sprint, bow, zoom, etc.); base FOV comes from renderer options. */
51
+ fovMultiplier: 1,
50
52
 
51
53
  cameraSpectatingEntity: undefined as number | undefined,
52
54
 
@@ -72,7 +72,8 @@ export const RENDERER_DEFAULT_OPTIONS = {
72
72
  viewBobbing: true,
73
73
  dayCycleAndLighting: true,
74
74
  keepChunksDistance: 1,
75
- gpuPreference: 'default' as RendererGpuPreference
75
+ gpuPreference: 'default' as RendererGpuPreference,
76
+ fov: 75
76
77
  } as const
77
78
 
78
79
  /** App options storage shape for renderer-owned keys. */
@@ -226,6 +227,12 @@ export const RENDERER_OPTIONS_META: Partial<Record<RendererDefaultOptionKey, Ren
226
227
  max: 5,
227
228
  unit: ''
228
229
  },
230
+ fov: {
231
+ min: 30,
232
+ max: 110,
233
+ unit: '°',
234
+ text: 'Field of view'
235
+ },
229
236
  gpuPreference: {
230
237
  text: 'GPU preference',
231
238
  tooltip: 'WebGL power preference. Requires reload / backend restart to apply.',
@@ -260,6 +267,7 @@ export const RENDERER_RENDER_GUI_SECTIONS: ReadonlyArray<{
260
267
  'renderEars',
261
268
  'showHand',
262
269
  'viewBobbing',
270
+ 'fov',
263
271
  'keepChunksDistance',
264
272
  'highlightBlockColor',
265
273
  'clipWorldBelowY'
@@ -65,6 +65,9 @@ export class WorldRendererThree extends WorldRendererCommon {
65
65
  cursorBlock: CursorBlock
66
66
  onRender: Array<(deltaTime: number) => void> = []
67
67
  private lastRenderTime = 0
68
+ private animatedFov = 0
69
+ private lastFovAnimTime = 0
70
+ private static readonly FOV_TRANSITION_MS = 200
68
71
  cameraShake: CameraShake
69
72
  cameraContainer!: THREE.Object3D
70
73
  media: ThreeJsMedia
@@ -1055,10 +1058,42 @@ export class WorldRendererThree extends WorldRendererCommon {
1055
1058
  }
1056
1059
 
1057
1060
  setCinimaticFov(fov: number): void {
1061
+ this.animatedFov = fov
1058
1062
  this.camera.fov = fov
1059
1063
  this.camera.updateProjectionMatrix()
1060
1064
  }
1061
1065
 
1066
+ private updateSmoothFov(): void {
1067
+ if (this.cinimaticScript.running) return
1068
+
1069
+ const baseFov = this.displayOptions.inWorldRenderingConfig.fov
1070
+ const mult = this.playerStateReactive.fovMultiplier
1071
+ const targetFov = baseFov * (Number.isFinite(mult) ? mult : 1)
1072
+
1073
+ const now = performance.now()
1074
+ if (this.animatedFov === 0) {
1075
+ this.animatedFov = targetFov
1076
+ }
1077
+
1078
+ if (Math.abs(this.animatedFov - targetFov) >= 0.01) {
1079
+ const elapsed = now - this.lastFovAnimTime
1080
+ const progress = Math.min(elapsed / WorldRendererThree.FOV_TRANSITION_MS, 1)
1081
+ const easeOutCubic = (t: number) => 1 - (1 - t) ** 3
1082
+ this.animatedFov += (targetFov - this.animatedFov) * easeOutCubic(progress)
1083
+ if (Math.abs(this.animatedFov - targetFov) < 0.01) {
1084
+ this.animatedFov = targetFov
1085
+ }
1086
+ } else {
1087
+ this.animatedFov = targetFov
1088
+ }
1089
+ this.lastFovAnimTime = now
1090
+
1091
+ if (this.camera.fov !== this.animatedFov) {
1092
+ this.camera.fov = this.animatedFov
1093
+ this.camera.updateProjectionMatrix()
1094
+ }
1095
+ }
1096
+
1062
1097
  updateCamera(pos: Vec3 | null, yaw: number, pitch: number): void {
1063
1098
  // Skip position/rotation updates if cinematic script is running
1064
1099
  if (this.cinimaticScript.running) {
@@ -1200,11 +1235,10 @@ export class WorldRendererThree extends WorldRendererCommon {
1200
1235
  const cameraPos = this.getCameraPosition()
1201
1236
  this.skyboxRenderer.update(cameraPos, this.viewDistance)
1202
1237
 
1203
- const sizeOrFovChanged = sizeChanged || this.displayOptions.inWorldRenderingConfig.fov !== this.camera.fov
1204
- if (sizeOrFovChanged) {
1238
+ this.updateSmoothFov()
1239
+ if (sizeChanged) {
1205
1240
  const size = this.renderer.getSize(new THREE.Vector2())
1206
1241
  this.camera.aspect = size.width / size.height
1207
- this.camera.fov = this.displayOptions.inWorldRenderingConfig.fov
1208
1242
  this.camera.updateProjectionMatrix()
1209
1243
  }
1210
1244