component
Lamp
Lamp that emits a point light.
⌖ Explore the library in 3D → · View as Markdown
Add it
npx @runek/cli add lamp
Pulls @react-three/fiber@^9.6.1, @react-three/rapier@^2.2.0, @runek/core@^0.15.0, three@^0.184.0.
Use it
import { Lamp } from './runek/Lamp'
<Lamp position={[0, 0, 0]} />
Or as a node in a world file (worlds as data):
{ "type": "Lamp", "props": { "position": [0, 0, 0] } }
Props
| Prop | Type | Default | Description |
|---|---|---|---|
position |
[x, y, z] |
[0, 0, 0] |
Position [x, y, z] in units (1 unit = 1 m, Y-up). |
rotation |
[x, y, z] |
[0, 0, 0] |
Euler rotation [x, y, z] in radians. |
seed |
number |
Accepted for the component contract; this component has no seeded variation yet. | |
height |
number |
1.6 |
Height, in units. |
color |
color |
palette metal |
Base + pole color. Defaults to the world palette’s metal slot. |
shadeColor |
color |
"#e9d8a6" |
|
lightColor |
color |
"#ffe8c2" |
|
intensity |
number |
18 |
|
flicker |
number |
0.08 |
Candle-like intensity flicker, 0–1; 0 holds the light steady. |
Registry manifest
registry manifest /r/components/lamp.json Self-contained JSON: inlined source plus resolved dependencies, exactly whatrunek add lamp fetches.
Browse the whole catalog in the gallery →.
Source (Lamp.tsx)
import { useFrame } from '@react-three/fiber'
import { CuboidCollider, RigidBody } from '@react-three/rapier'
import { useWorld, type Vec3 } from '@runek/core'
import { useRef } from 'react'
import type { PointLight } from 'three'
export interface LampProps {
position?: Vec3
rotation?: Vec3
/** Accepted for the component contract; this component has no seeded variation yet. */
seed?: number
height?: number
/** Base + pole color. Defaults to the world palette's `metal` slot. */
color?: string
shadeColor?: string
lightColor?: string
intensity?: number
/** Candle-like intensity flicker, 0–1; 0 holds the light steady. */
flicker?: number
}
export function Lamp({
position = [0, 0, 0],
rotation = [0, 0, 0],
height = 1.6,
color,
shadeColor = '#e9d8a6',
lightColor = '#ffe8c2',
intensity = 18,
flicker = 0.08,
}: LampProps) {
const { unit, palette } = useWorld()
const metalColor = color ?? palette.metal
const h = height * unit
const baseR = 0.16 * unit
const poleR = 0.02 * unit
const shadeR = 0.19 * unit
const shadeH = 0.26 * unit
const poleH = h - shadeH
const lightRef = useRef<PointLight>(null)
useFrame(({ clock }) => {
if (!lightRef.current || flicker <= 0) return
const t = clock.elapsedTime
// layered sines read as a candle without any per-frame randomness
const n = Math.sin(t * 9.3) * 0.5 + Math.sin(t * 23.7) * 0.3 + Math.sin(t * 41.1) * 0.2
lightRef.current.intensity = intensity * (1 + n * flicker)
})
return (
<RigidBody type="fixed" colliders={false} position={position} rotation={rotation}>
<CuboidCollider args={[baseR, h / 2, baseR]} position={[0, h / 2, 0]} />
<mesh castShadow position={[0, 0.025 * unit, 0]}>
<cylinderGeometry args={[baseR, baseR, 0.05 * unit, 24]} />
<meshStandardMaterial color={metalColor} metalness={0.4} roughness={0.5} />
</mesh>
<mesh castShadow position={[0, poleH / 2, 0]}>
<cylinderGeometry args={[poleR, poleR, poleH, 12]} />
<meshStandardMaterial color={metalColor} metalness={0.4} roughness={0.5} />
</mesh>
<mesh castShadow position={[0, h - shadeH / 2, 0]}>
<coneGeometry args={[shadeR, shadeH, 24, 1, true]} />
<meshStandardMaterial
color={shadeColor}
emissive={shadeColor}
emissiveIntensity={0.4}
side={2}
/>
</mesh>
<pointLight
ref={lightRef}
position={[0, h - shadeH, 0]}
color={lightColor}
intensity={intensity}
distance={12 * unit}
decay={2}
/>
</RigidBody>
)
}
Lamp.groundSitting = true