本文へ移動
cccskills
無料GitHub で公開

globe-particles

Create a globe-like 3D particle visualization with a dense luminous spherical core and thinner orbital ring or flattened disc. Use when a design needs a premium planetary, orbital, synthesized data-globe effect rendered with real WebGL/Three.js particles, not generic starfields or full page layout changes.

インストール方法を見る

含まれるファイル(9)

  • SKILL.md9.7 KB
  • demo/assets/page-01-fa51902b-c2a4-4c33-a96e-a8f1ef67edc6-1600w.jpg46.4 KB
  • demo/assets/page-02-4f5668c5-fc4a-44e0-bc5e-a664189d3c31-1600w.jpg212.3 KB
  • demo/assets/page-03-2f563338-39fa-47ea-9761-658d4f3f84db-1600w.jpg292.0 KB
  • demo/assets/source-preview.jpg108.9 KB
  • demo/index.html45.9 KB
  • demo/preview.jpg56.6 KB
  • demo/PROMPT.md3.2 KB
  • demo/source.json3.9 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Globe Particles

Scope

  • Apply only to a globe-like 3D particle visualization.
  • Do not change full page layout, copy, or unrelated motion systems.
  • Use for planetary, orbital, infrastructure, or synthesized data-globe effects.
  • Keep the core neutral or white-hot and derive ring/glow accents from the design's primary color.

Visual Target

  • Dense spherical core of luminous points.
  • Thinner outer orbital ring or flattened disc around the sphere.
  • Clear globe silhouette with tilt, depth, and layered particle density.
  • Dark atmospheric background, restrained glow, clean structure, and subtle sci-fi depth.
  • Premium and cinematic, not playful or noisy.

HTML And CSS

<div class="globe-particles-shell">
  <canvas class="globe-particles-canvas" data-globe-particles></canvas>
</div>
.globe-particles-shell {
  position: relative;
  width: min(100%, 760px);
  aspect-ratio: 1 / 1;
}

.globe-particles-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
}

Particle Shader

Use circular shader points so particles stay crisp and luminous.

const globeParticleVertex = `
attribute float a_size;
attribute float a_layer;

uniform float u_time;
uniform float u_pointSize;

varying float v_layer;
varying float v_depth;
varying float v_falloff;

void main() {
  vec3 pos = position;
  float breathe = 1.0 + sin(u_time * 0.65 + a_layer * 4.0) * 0.012;
  pos *= breathe;

  vec4 mvPosition = modelViewMatrix * vec4(pos, 1.0);
  gl_PointSize = u_pointSize * a_size * (1.0 / max(0.18, -mvPosition.z));
  gl_Position = projectionMatrix * mvPosition;

  v_layer = a_layer;
  v_depth = smoothstep(-1.8, 1.8, pos.z);
  v_falloff = smoothstep(2.45, 0.25, length(pos));
}
`;

const globeParticleFragment = `
precision highp float;

uniform vec3 u_coreColor;
uniform vec3 u_accentColor;

varying float v_layer;
varying float v_depth;
varying float v_falloff;

void main() {
  vec2 uv = gl_PointCoord - 0.5;
  float d = length(uv);
  float alpha = smoothstep(0.5, 0.0, d);
  alpha *= alpha;

  vec3 color = mix(u_coreColor, u_accentColor, smoothstep(0.35, 1.0, v_layer));
  color += vec3(1.0) * v_depth * 0.08;
  color = mix(color * 0.42, color, clamp(v_falloff + v_layer * 0.28, 0.0, 1.0));
  alpha *= mix(0.52, 1.0, clamp(v_falloff + v_layer * 0.24, 0.0, 1.0));

  gl_FragColor = vec4(color, alpha);
}
`;

Three.js Recipe

import * as THREE from "three";

function hexToRgb01(hex) {
  const clean = hex.replace("#", "").trim();
  const value = clean.length === 3
    ? clean.split("").map((char) => char + char).join("")
    : clean;

  return new THREE.Color(
    parseInt(value.slice(0, 2), 16) / 255,
    parseInt(value.slice(2, 4), 16) / 255,
    parseInt(value.slice(4, 6), 16) / 255
  );
}

function buildGlobeParticleGeometry(options = {}) {
  const sphereCount = options.sphereCount || 2600;
  const ringCount = options.ringCount || 1300;
  const radius = options.radius || 1.35;
  const ringRadius = options.ringRadius || 2.05;
  const ringThickness = options.ringThickness || 0.12;
  const total = sphereCount + ringCount;

  const positions = new Float32Array(total * 3);
  const sizes = new Float32Array(total);
  const layers = new Float32Array(total);

  for (let i = 0; i < sphereCount; i++) {
    const z = Math.random() * 2 - 1;
    const theta = Math.random() * Math.PI * 2;
    const r = radius * (0.58 + Math.pow(Math.random(), 0.42) * 0.42);
    const root = Math.sqrt(1 - z * z);
    const index = i * 3;

    positions[index] = Math.cos(theta) * root * r;
    positions[index + 1] = Math.sin(theta) * root * r;
    positions[index + 2] = z * r;
    sizes[i] = 0.72 + Math.random() * 0.72;
    layers[i] = Math.random() * 0.28;
  }

  for (let i = 0; i < ringCount; i++) {
    const pointIndex = sphereCount + i;
    const angle = Math.random() * Math.PI * 2;
    const r = ringRadius + (Math.random() - 0.5) * ringThickness;
    const y = (Math.random() - 0.5) * ringThickness * 0.58;
    const index = pointIndex * 3;

    positions[index] = Math.cos(angle) * r;
    positions[index + 1] = y;
    positions[index + 2] = Math.sin(angle) * r;
    sizes[pointIndex] = 0.62 + Math.random() * 0.58;
    layers[pointIndex] = 0.72 + Math.random() * 0.28;
  }

  const geometry = new THREE.BufferGeometry();
  geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
  geometry.setAttribute("a_size", new THREE.BufferAttribute(sizes, 1));
  geometry.setAttribute("a_layer", new THREE.BufferAttribute(layers, 1));
  return geometry;
}

function initGlobeParticles(canvas, options = {}) {
  if (!canvas) return () => {};

  const renderer = new THREE.WebGLRenderer({
    canvas,
    antialias: true,
    alpha: true,
  });
  renderer.setClearColor(0x000000, 0);
  renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, options.maxDpr || 1.6));
  renderer.outputColorSpace = THREE.SRGBColorSpace;

  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(38, 1, 0.1, 100);
  camera.position.set(0, 0, options.cameraDistance || 5.6);

  const accent = options.accentColor
    ? new THREE.Color(options.accentColor)
    : hexToRgb01(getComputedStyle(document.documentElement).getPropertyValue("--brand-accent").trim() || "#8b5cf6");

  const geometry = buildGlobeParticleGeometry(options);
  const material = new THREE.ShaderMaterial({
    vertexShader: globeParticleVertex,
    fragmentShader: globeParticleFragment,
    transparent: true,
    depthWrite: false,
    blending: THREE.AdditiveBlending,
    uniforms: {
      u_time: { value: 0 },
      u_pointSize: { value: options.pointSize || 18 },
      u_coreColor: { value: new THREE.Color(options.coreColor || 0xf8fafc) },
      u_accentColor: { value: accent },
    },
  });

  const particles = new THREE.Points(geometry, material);
  particles.rotation.x = options.tiltX ?? -0.42;
  particles.rotation.z = options.tiltZ ?? 0.22;
  scene.add(particles);

  const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
  const pointer = new THREE.Vector2(0, 0);
  let rafId = 0;

  function resize() {
    const width = Math.max(1, canvas.clientWidth);
    const height = Math.max(1, canvas.clientHeight);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, options.maxDpr || 1.6));
    renderer.setSize(width, height, false);
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
  }

  function handlePointerMove(event) {
    const rect = canvas.getBoundingClientRect();
    pointer.x = ((event.clientX - rect.left) / rect.width - 0.5) * 2;
    pointer.y = ((event.clientY - rect.top) / rect.height - 0.5) * 2;
  }

  function render(time = 0) {
    const t = time * 0.001;
    material.uniforms.u_time.value = t;

    const mouseStrength = options.mouseStrength ?? 0.08;
    const breath = reduceMotion ? 0 : Math.sin(t * 0.55) * 0.045;
    particles.rotation.y = t * (options.rotationSpeed || 0.12);
    particles.rotation.x = (options.tiltX ?? -0.42) + pointer.y * mouseStrength;
    particles.rotation.z = (options.tiltZ ?? 0.22) + pointer.x * mouseStrength;
    particles.scale.setScalar(1 + breath);

    renderer.render(scene, camera);
    if (!reduceMotion) rafId = requestAnimationFrame(render);
  }

  function handleResize() {
    cancelAnimationFrame(rafId);
    resize();
    render();
  }

  resize();
  render();
  window.addEventListener("resize", handleResize);
  window.addEventListener("pointermove", handlePointerMove);

  return () => {
    cancelAnimationFrame(rafId);
    window.removeEventListener("resize", handleResize);
    window.removeEventListener("pointermove", handlePointerMove);
    geometry.dispose();
    material.dispose();
    renderer.dispose();
  };
}

const cleanupGlobe = initGlobeParticles(document.querySelector("[data-globe-particles]"), {
  sphereCount: 2600,
  ringCount: 1300,
  accentColor: "#8b5cf6",
  radius: 1.35,
  ringRadius: 2.05,
  rotationSpeed: 0.12,
  mouseStrength: 0.08,
});

Tuning Knobs

  • Density: tune sphereCount and ringCount separately.
  • Scale: tune radius, ringRadius, ringThickness, and cameraDistance.
  • Color: keep coreColor neutral; derive accentColor from the brand primary.
  • Motion: tune rotationSpeed, tiltX, tiltZ, mouseStrength, and breathing amplitude.
  • Glow: tune pointSize, additive blending, and particle count so the shape stays crisp.
  • Performance: lower particle counts or cap maxDpr before changing the visual structure.

Taste Rules

  • The silhouette must read as a globe, not a loose starfield.
  • The ring should feel orbital and tilted, not like a flat decorative underline.
  • Use restrained glow; let density and depth create the premium feel.
  • Keep mouse response gentle so the object drifts rather than swings.
  • Put the globe over a dark background or inside a dark atmospheric shell.

Avoid

  • Generic starfield noise with no spherical structure.
  • Oversized particles or bloom that destroys the globe silhouette.
  • Hardcoded accent colors when the design has a clear primary color.
  • Wild cursor interaction or fast spinning.
  • Dense fog that turns the object into a blurry blob.

Quick Checks

  • Sphere and ring are distinct particle populations.
  • Core reads mostly neutral or white-hot.
  • Accent color appears on ring, highlights, or glow.
  • Tilt reveals the ring and globe depth.
  • Reduced motion renders a still or near-still object.
  • Geometry, material, renderer, listeners, and RAF are cleaned up.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Build convincing woven cloth in Three.js, with a thread-level weave normal map, sheen and anisotropic highlights, folds that never stretch the texture, hems with thickness, stitches, seams, frayed edges, fold occlusion, dye and wear variation, and light passing through thin fabric. Use for linen, silk, wool, canvas, curtains, banners, cloaks, tablecloths, tapestries or any 3D drape that currently looks like a plastic sheet, a stretched texture, or a flat coloured plane.

日本語の概要は準備中です。原文の説明を表示しています。

MengTo/Skills6,7402026年10月6日 更新

Build recognizable falling leaves in world space using instanced geometry, independent tumble, coupled sideways drift, shared wind, scene occlusion, and camera-aware recycling. Use for 3D autumn leaves or drifting foliage in Three.js and similar scenes; use falling-leaves for a 2D canvas overlay.

日本語の概要は準備中です。原文の説明を表示しています。

MengTo/Skills6,7402026年10月6日 更新

Add coordinated spring, summer, fall, and winter states to a 3D scene, blending foliage, sunlight, sky, ground materials, snow, and particles without rebuilding the world. Use for seasonal controls, architectural walkthroughs, and outdoor scenes with four-season transitions.

日本語の概要は準備中です。原文の説明を表示しています。

MengTo/Skills6,7402026年10月6日 更新

Create or integrate highly detailed 3D models with smooth silhouettes, shaped surfaces, believable bevels, and close-up geometry, then prepare suitable runtime LODs and loading. Use when a user requests high polygon counts, ultra-realistic models, detailed architectural assets, or removal of visibly faceted geometry.

日本語の概要は準備中です。原文の説明を表示しています。

MengTo/Skills6,7402026年10月6日 更新

Build sharp, physically coherent high-resolution materials for 3D rendering with appropriate PBR maps, texel density, UV direction, mipmaps, anisotropic filtering, and progressive asset delivery. Use for detailed wood, stone, fabric, foliage, and architectural close-ups without excessive download or GPU memory costs.

日本語の概要は準備中です。原文の説明を表示しています。

MengTo/Skills6,7402026年10月6日 更新

Build hyperrealistic PBR metal in Three.js: steel, brass, gold, copper and iron as true conductors (metalness 1, measured F0 tint, no albedo) with roughness-varied finishes (polished, brushed anisotropic, aged with patina and worn edges) lit by a dark HDR studio of real bright window cards prefiltered with PMREM. Use when metal looks like grey plastic, a dull blur, or a black hole; when blades, tools, rings, ingots, hardware or product metal need reflections with edges and structure; or when a finish needs scratches, streaks, fingerprints and bevels that catch light.

日本語の概要は準備中です。原文の説明を表示しています。

MengTo/Skills6,7402026年10月6日 更新

MengTo のスキルをすべて見る

このスキルの問題を報告する