pixel-planet
pixel-planet-registry/pixel-planetFreeComponent
A collection of 3D pixel planets built with React Three Fiber.
Live preview
live · rendered by the registry
Rendered by Pixel Planet Registry on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://pixel-planet.fartlabs.org/r/pixel-planet.jsonSource
1"use client"23import { Canvas, useFrame } from "@react-three/fiber"4import { Stars } from "@react-three/drei"5import { useEffect, useMemo, useRef, useState } from "react"6import { generatePlanetByType, type PlanetOptions } from "../lib/utils"7import { Timer } from "three"89export interface PixelPlanetProps {10 type:11 | "ice"12 | "gas_giant_1"13 | "gas_giant_2"14 | "asteroid"15 | "star"16 | "lava"17 | "dry"18 | "earth"19 | "no_atmosphere"20 seed: number2122 cameraZ?: number23 /**24 * advanced customization options for the planet.25 */26 advanced?: PlanetOptions27 className?: string28 stars?: boolean29 orbitControls?: boolean30 orbitControlsSensitivity?: number31}3233const mapTypeToLabel: Record<PixelPlanetProps["type"], string> = {34 ice: "Ice Planet",35 gas_giant_1: "Gas giant 1",36 gas_giant_2: "Gas giant 2",37 asteroid: "Asteroid",38 star: "Star",39 lava: "Lava Planet",40 dry: "Dry Planet",41 earth: "Earth Planet",42 no_atmosphere: "No atmosphere",43}4445function CameraUpdater({ cameraZ }: { cameraZ: number }) {46 useFrame(({ camera }) => {47 if (camera.position.z !== cameraZ) {48 camera.position.set(0, 0, cameraZ)49 camera.lookAt(0, 0, 0)50 }51 })52 return null53}5455function PlanetContent({56 type,57 seed,58 advanced: options,59 rotationOffset = 0,60}: PixelPlanetProps & { rotationOffset?: number }) {61 const planetLabel = mapTypeToLabel[type]6263 // Generate planet group when type changes64 const planet = useMemo(() => {65 return generatePlanetByType(planetLabel, options)66 }, [planetLabel, options])6768 // Update seed when it changes69 useEffect(() => {70 if (!planet) return71 // eslint-disable-next-line @typescript-eslint/no-explicit-any72 planet.children.forEach((layer: any) => {73 if (layer.material && layer.material.uniforms) {74 if (layer.material.uniforms["seed"]) {75 layer.material.uniforms["seed"].value = seed76 }77 }78 })79 }, [planet, seed])8081 const timer = useMemo(() => new Timer(), [])8283 // Animation loop - update time and manual offset for texture scrolling84 useFrame(() => {85 if (!planet) return8687 timer.update()8889 // eslint-disable-next-line @typescript-eslint/no-explicit-any90 planet.children.forEach((layer: any) => {91 if (layer.material && layer.material.uniforms) {92 if (layer.material.uniforms["time"]) {93 layer.material.uniforms["time"].value =94 timer.getElapsed() + rotationOffset95 }96 }97 })98 })99100// … truncated
What it pulls in
npm packages
