Junkerposts
■
みせられない
完全に私的なメモ
├
<!DOCTYPE html>
<html>
<head>
<title>A-Frame - コメントリンク機能</title>
<script src="https://aframe.io/releases/1.7.0/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-look-at-component@0.8.0/dist/aframe-look-at-component.min.js"></script>
<script src="https://unpkg.com/aframe-troika-text/dist/aframe-troika-text.min.js"></script>
<script>
// --- プレイヤー移動制御用カスタムコンポーネント ('camera-relative-controls') ---
// (変更なし - 省略)
AFRAME.registerComponent('camera-relative-controls', { schema: { targetSpeed: { type: 'number', default: 5 }, acceleration: { type: 'number', default: 10 }, damping: { type: 'number', default: 8 }, brakingDeceleration: { type: 'number', default: 20 }, enabled: { type: 'boolean', default: true } }, init: function () { this.keys = {}; this.thumbstickInput = { x: 0, y: 0 }; this.currentVelocity = new THREE.Vector3(); this.ZERO_VECTOR = new THREE.Vector3(); this.cameraDirection = new THREE.Vector3(); this.cameraRight = new THREE.Vector3(); this.moveDirection = new THREE.Vector3(); this.desiredVelocity = new THREE.Vector3(); this.cameraWorldQuaternion = new THREE.Quaternion(); this.cameraEl = this.el.querySelector('[camera]'); this.isReady = false; if (!this.cameraEl) { console.error('camera-relative-controls: カメラエンティティが見つかりません。'); } this.el.sceneEl.addEventListener('loaded', () => { this.leftHand = document.getElementById('leftHand'); if (this.leftHand) { this.leftHand.addEventListener('thumbstickmoved', this.onThumbstickMoved.bind(this)); } else { console.warn("camera-relative-controls: 左手コントローラー(#leftHand)が見つかりません。"); } }); this.onKeyDown = this.onKeyDown.bind(this); this.onKeyUp = this.onKeyUp.bind(this); window.addEventListener('keydown', this.onKeyDown); window.addEventListener('keyup', this.onKeyUp); }, remove: function () { window.removeEventListener('keydown', this.onKeyDown); window.removeEventListener('keyup', this.onKeyUp); if (this.leftHand) { try { this.leftHand.removeEventListener('thumbstickmoved', this.onThumbstickMoved.bind(this)); } catch(e) { console.warn("camera-relative-controls: スティックリスナー解除失敗の可能性あり"); } } }, onThumbstickMoved: function (evt) { this.thumbstickInput.x = evt.detail.x; this.thumbstickInput.y = evt.detail.y; }, tick: function (time, timeDelta) { if (!this.data.enabled) return; if (!this.isReady) { if (this.cameraEl && this.cameraEl.object3D && this.cameraEl.object3D.matrixWorld) { this.isReady = true; } else { if (!this.cameraEl) { this.cameraEl = this.el.querySelector('[camera]'); } return; } } if (!this.cameraEl || !this.cameraEl.object3D) { return; } const el = this.el; const data = this.data; const position = el.object3D.position; const dt = timeDelta / 1000; this.cameraEl.object3D.getWorldQuaternion(this.cameraWorldQuaternion); this.cameraDirection.set(0, 0, -1).applyQuaternion(this.cameraWorldQuaternion); if (this.cameraDirection.lengthSq() > 0.0001) this.cameraDirection.normalize(); this.cameraRight.set(1, 0, 0).applyQuaternion(this.cameraWorldQuaternion); this.cameraRight.y = 0; if (this.cameraRight.lengthSq() > 0.0001) this.cameraRight.normalize(); this.moveDirection.set(0, 0, 0); if (this.keys['KeyW'] || this.keys['ArrowUp']) { this.moveDirection.add(this.cameraDirection); } if (this.keys['KeyS'] || this.keys['ArrowDown']) { this.moveDirection.sub(this.cameraDirection); } if (this.keys['KeyA'] || this.keys['ArrowLeft']) { this.moveDirection.sub(this.cameraRight); } if (this.keys['KeyD'] || this.keys['ArrowRight']) { this.moveDirection.add(this.cameraRight); } if (Math.abs(this.thumbstickInput.y) > 0.1) { const forwardBackward = this.cameraDirection.clone().multiplyScalar(-this.thumbstickInput.y); this.moveDirection.add(forwardBackward); } if (Math.abs(this.thumbstickInput.x) > 0.1) { const leftRight = this.cameraRight.clone().multiplyScalar(this.thumbstickInput.x); this.moveDirection.add(leftRight); } const isInputActive = this.moveDirection.lengthSq() > 0.0001; if (isInputActive) { this.moveDirection.normalize(); } let lerpFactor = data.damping; const isCurrentlyMoving = this.currentVelocity.lengthSq() > 0.01; if (isInputActive) { let isOpposingInput = false; if (isCurrentlyMoving) { const dotProduct = this.currentVelocity.dot(this.moveDirection); if (dotProduct < -0.1) { isOpposingInput = true; } } if (isOpposingInput) { this.desiredVelocity.copy(this.ZERO_VECTOR); lerpFactor = data.brakingDeceleration; } else { this.desiredVelocity.copy(this.moveDirection).multiplyScalar(data.targetSpeed); lerpFactor = data.acceleration; } } else { this.desiredVelocity.copy(this.ZERO_VECTOR); lerpFactor = data.damping; } const effectiveLerpFactor = 1.0 - Math.exp(-lerpFactor * dt); this.currentVelocity.lerp(this.desiredVelocity, effectiveLerpFactor); if (this.currentVelocity.lengthSq() < 0.0001) { this.currentVelocity.copy(this.ZERO_VECTOR); } if (this.currentVelocity.lengthSq() > 0) { const deltaPosition = this.currentVelocity.clone().multiplyScalar(dt); position.add(deltaPosition); } }, onKeyDown: function (event) { if (!this.data.enabled) { return; } if (['KeyW', 'ArrowUp', 'KeyS', 'ArrowDown', 'KeyA', 'ArrowLeft', 'KeyD', 'ArrowRight'].includes(event.code)) { this.keys[event.code] = true; } }, onKeyUp: function (event) { if (this.keys[event.code] !== undefined) { delete this.keys[event.code]; } } });
// --- 立方体をランダムに回転させるカスタムコンポーネント ('random-rotate') ---
// (変更なし - 省略)
AFRAME.registerComponent('random-rotate', { schema: { maxSpeed: { type: 'number', default: 5 } }, init: function () { this.axis = new THREE.Vector3(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5).normalize(); const speed = ((Math.random() * 0.8) + 0.2) * this.data.maxSpeed * (Math.random() < 0.5 ? 1 : -1); this.speedRad = THREE.MathUtils.degToRad(speed); this.deltaRotationQuaternion = new THREE.Quaternion(); }, tick: function (time, timeDelta) { const dt = timeDelta / 1000; const angle = this.speedRad * dt; this.deltaRotationQuaternion.setFromAxisAngle(this.axis, angle); this.el.object3D.quaternion.multiplyQuaternions(this.deltaRotationQuaternion, this.el.object3D.quaternion); } });
</script>
</head>
<body>
<a-scene id="myScene" background="color: #000000" vr-mode-ui="enabled: true">
<a-entity id="rig" position="0 0 5"
camera-relative-controls="targetSpeed: 250; acceleration: 3; damping: 5; brakingDeceleration: 1;">
<a-entity id="camera" camera="far: 20000;" look-controls position="0 1.6 0">
<a-entity id="mouseCursor" cursor="rayOrigin: mouse; fuse: false;" raycaster="objects: .clickableObject, .clickableButton; far: 3000;" position="0 0 -1" geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03;" material="color: black; shader: flat; opacity: 0.7;"> <a-animation begin="click" easing="ease-in" attribute="scale" fill="backwards" from="0.1 0.1 0.1" to="1 1 1" dur="150"></a-animation> </a-entity>
</a-entity>
<a-entity id="leftHand" oculus-touch-controls="hand: left; model: true;"></a-entity>
<a-entity id="rightHand" oculus-touch-controls="hand: right; model: true;" raycaster="objects: .clickableObject, .clickableButton; far: 3000; enabled: true;" laser-controls="hand: right; model: false; lineColor: white; lineOpacity: 0.75" ></a-entity>
</a-entity>
<a-entity light="type: ambient; color: #444"></a-entity>
<a-entity light="type: directional; color: #FFF; intensity: 0.8" position="-1 1.5 1"></a-entity>
<a-entity light="type: directional; color: #AAA; intensity: 0.4" position="1 1 -1"></a-entity>
<a-entity id="infoPanel" visible="false" position="0 -1000 0" look-at="[camera]">
<a-plane id="panelBackground" width="50" height="24" color="#333" opacity="0.9" side="double"></a-plane>
<a-entity id="panelText" troika-text="value: Placeholder; color: white; fontSize: 0.72; maxWidth: 46; align: center; anchorX: center; anchorY: middle; baseline: middle;" position="0 0 0.05"> </a-entity>
<a-cone id="prevButton" class="clickableButton" position="-20.0 0 0.1" rotation="0 0 90" radius-bottom="1.2" radius-top="0" height="2.0" material="color: #CCC; shader: flat; opacity: 0.8;"> </a-cone>
<a-cone id="nextButton" class="clickableButton" position="20.0 0 0.1" rotation="0 0 -90" radius-bottom="1.2" radius-top="0" height="2.0" material="color: #CCC; shader: flat; opacity: 0.8;"> </a-cone>
<a-sphere id="closeButton" class="clickableButton" position="24 11 0.1" radius="1.5" color="red" shader="flat"> </a-sphere>
<a-sphere id="linkButton" class="clickableButton" visible="false"
position="-24 -11 0.1" radius="1.5" color="green" shader="flat">
</a-sphere>
</a-entity>
<script>
// --- グローバル変数とDOM要素の取得 ---
const sceneEl = document.getElementById('myScene');
const infoPanelEl = document.getElementById('infoPanel');
const panelTextEl = document.getElementById('panelText');
const cameraEl = document.getElementById('camera');
const prevButtonEl = document.getElementById('prevButton');
const nextButtonEl = document.getElementById('nextButton');
const closeButtonEl = document.getElementById('closeButton');
const mouseCursorEl = document.getElementById('mouseCursor');
const linkButtonEl = document.getElementById('linkButton'); // ★★★ リンクボタン要素取得 ★★★
let rightHandEl = null;
// パネルの表示オフセット距離 (デフォルト値を5に変更済み)
const PANEL_OFFSET_FROM_OBJECT = 5.0;
// ページごとのテキストスタイル定義 (変更なし)
const BASE_TEXT_STYLE = { maxWidth: 46, align: 'center', anchorX: 'center', anchorY: 'middle', baseline: 'middle' };
const PAGE_TEXT_STYLES = { 'index': { ...BASE_TEXT_STYLE, fontSize: 0.72, color: 'white' }, 'color': { ...BASE_TEXT_STYLE, fontSize: 0.65, color: '#A0F0A0' }, 'size': { ...BASE_TEXT_STYLE, fontSize: 0.80, color: '#FFEC8B' }, 'comment': { ...BASE_TEXT_STYLE, fontSize: 0.70, color: '#ADD8E6' } };
// ★★★ 立方体ごとのコメントデータと、そのコメント用の文字色、リンクURLを定義 ★★★
const CUBE_COMMENTS = {
1: { text: ["最初の立方体だ!", "何か秘密が隠されているかもしれない…"], color: "#FF6347" },
5: { text: ["これは5番目の特別な立方体。", "長いコメントもこのように複数ページにわたって表示できます。", "素晴らしい発見だ!"], color: "#FFFF00" },
10: { text: ["ようこそ、宇宙の果てへ。\n詳細は下記リンクで!"], link: "https://aframe.io/docs/" }, // 色指定なし、リンクあり
15: { text: ["ただのコメント。"], link: "https://google.com", color: "#FFC0CB" }, // 色指定あり、リンクあり
25: { text: ["折り返し地点です。"] }, // リンクも色指定もなし
};
const DEFAULT_COMMENT_ARRAY_INFO = { text: ["コメントはありません"] }; // デフォルトコメント情報
// --- 定数定義 (変更なし) ---
const numSpheres = 60; const spread = 2000; const PAGES = ['index', 'color', 'size', 'comment']; const TOTAL_MAIN_PAGES = PAGES.length;
const targetWorldPosition = new THREE.Vector3(); const cameraWorldPosition = new THREE.Vector3(); const direction = new THREE.Vector3(); const panelPosition = new THREE.Vector3();
// --- 立方体生成ループ (変更なし) ---
for (let i = 0; i < numSpheres; i++) { const cubeEl = document.createElement('a-box'); const side = Math.random() * 10.0 + 0.5; const x = (Math.random() - 0.5) * spread; const y = Math.random() * (spread / 2) + side / 2; const z = (Math.random() - 0.5) * spread; const color = `hsl(${Math.random() * 360}, 50%, 75%)`; const sphereIndex = i + 1; cubeEl.setAttribute('width', side); cubeEl.setAttribute('height', side); cubeEl.setAttribute('depth', side); cubeEl.setAttribute('color', color); cubeEl.setAttribute('position', { x: x, y: y, z: z }); cubeEl.classList.add('clickableObject'); cubeEl.dataset.sphereIndex = sphereIndex; cubeEl.dataset.color = color; cubeEl.dataset.size = side.toFixed(2); cubeEl.setAttribute('random-rotate', {maxSpeed: 5}); cubeEl.addEventListener('click', handleSphereClick); sceneEl.appendChild(cubeEl); }
// --- ★★★ 情報パネルの表示更新関数 (リンクボタン表示制御追加) ★★★ ---
function updatePanelDisplay() {
if (!infoPanelEl.dataset.sphereIndex) return;
const index = parseInt(infoPanelEl.dataset.sphereIndex || '0', 10);
const sphereColor = infoPanelEl.dataset.color || 'N/A';
const size = infoPanelEl.dataset.size || 'N/A';
const commentInfo = JSON.parse(infoPanelEl.dataset.commentInfo || JSON.stringify(DEFAULT_COMMENT_ARRAY_INFO));
const commentsArray = commentInfo.text;
const specificCommentColor = commentInfo.color;
const activeLinkUrl = infoPanelEl.dataset.activeLinkUrl || ""; // ★ リンクURLを取得
const commentSubPageCount = parseInt(infoPanelEl.dataset.commentSubPageCount || '1', 10);
const commentSubPageIndex = parseInt(infoPanelEl.dataset.commentSubPageIndex || '0', 10);
const mainPageIndex = parseInt(infoPanelEl.dataset.currentPageIndex || '0', 10);
let displayText = '';
const pageType = PAGES[mainPageIndex];
let pageIndicator = `(${mainPageIndex + 1}/${TOTAL_MAIN_PAGES})`;
let currentStyle = { ...PAGE_TEXT_STYLES[pageType] } || { ...PAGE_TEXT_STYLES['index'] };
// ★★★ リンクボタンの表示制御 ★★★
if (pageType === 'comment' && activeLinkUrl) {
linkButtonEl.setAttribute('visible', true);
} else {
linkButtonEl.setAttribute('visible', false);
}
if (pageType === 'index') { displayText = `立方体: ${index}`; }
else if (pageType === 'color') { displayText = `色: ${sphereColor}`; }
else if (pageType === 'size') { displayText = `サイズ: ${size}`; }
else if (pageType === 'comment') {
displayText = `コメント:\n${commentsArray[commentSubPageIndex]}`;
pageIndicator = `(${mainPageIndex + 1}/${TOTAL_MAIN_PAGES} - コメント ${commentSubPageIndex + 1}/${commentSubPageCount})`;
if (specificCommentColor) { currentStyle.color = specificCommentColor; }
}
const finalDisplayText = `${pageIndicator}\n${displayText}`;
panelTextEl.setAttribute('troika-text', {
value: finalDisplayText, color: currentStyle.color, fontSize: currentStyle.fontSize,
maxWidth: currentStyle.maxWidth, align: currentStyle.align, anchorX: currentStyle.anchorX,
anchorY: currentStyle.anchorY, baseline: currentStyle.baseline
});
}
// --- ★★★ 立方体クリック時の処理 (リンクURL保存追加) ★★★ ---
function handleSphereClick(event) {
event.stopPropagation();
console.log("--- handleSphereClick triggered --- Target:", event.target.id || event.target.tagName);
const clickedCube = event.target;
if (!clickedCube.dataset.sphereIndex || !clickedCube.dataset.color || !clickedCube.dataset.size) {
console.error("Cube data missing from dataset!", clickedCube.dataset); return;
}
console.log("Cube data found:", clickedCube.dataset);
infoPanelEl.dataset.sphereIndex = clickedCube.dataset.sphereIndex;
infoPanelEl.dataset.color = clickedCube.dataset.color;
infoPanelEl.dataset.size = clickedCube.dataset.size;
infoPanelEl.dataset.currentPageIndex = '0';
const sphereIdx = parseInt(clickedCube.dataset.sphereIndex, 10);
const commentDataForThisCube = CUBE_COMMENTS[sphereIdx] || DEFAULT_COMMENT_ARRAY_INFO;
infoPanelEl.dataset.commentInfo = JSON.stringify(commentDataForThisCube);
infoPanelEl.dataset.commentSubPageCount = commentDataForThisCube.text.length.toString();
infoPanelEl.dataset.commentSubPageIndex = '0';
// ★★★ リンクURLを保存 (存在すれば) ★★★
infoPanelEl.dataset.activeLinkUrl = commentDataForThisCube.link || "";
console.log("Data (including link) stored in panel dataset.");
try { updatePanelDisplay(); console.log("updatePanelDisplay completed."); }
catch (e) { console.error("Error during updatePanelDisplay:", e); return; }
try { clickedCube.object3D.getWorldPosition(targetWorldPosition); cameraEl.object3D.getWorldPosition(cameraWorldPosition); const cubeSide = parseFloat(clickedCube.dataset.size || 0); const offsetDistance = cubeSide / 2 + PANEL_OFFSET_FROM_OBJECT; direction.subVectors(cameraWorldPosition, targetWorldPosition).normalize(); panelPosition.copy(targetWorldPosition).addScaledVector(direction, offsetDistance); infoPanelEl.object3D.position.copy(panelPosition); console.log("Panel position calculated and applied."); }
catch(e) { console.error("Error during position calculation:", e); return; }
infoPanelEl.setAttribute('visible', true);
console.log("Panel visibility set to true. --- handleSphereClick end ---");
}
// --- パネルのボタンクリック処理 (変更なし) ---
prevButtonEl.addEventListener('click', function (event) { /* ... (省略) ... */ event.stopPropagation(); if (!infoPanelEl.getAttribute('visible')) return; let mainPageIndex = parseInt(infoPanelEl.dataset.currentPageIndex || '0', 10); let commentSubPageIndex = parseInt(infoPanelEl.dataset.commentSubPageIndex || '0', 10); const commentSubPageCount = parseInt(infoPanelEl.dataset.commentSubPageCount || '1', 10); const currentCommentInfo = JSON.parse(infoPanelEl.dataset.commentInfo || JSON.stringify(DEFAULT_COMMENT_ARRAY_INFO)); if (PAGES[mainPageIndex] === 'comment' && commentSubPageCount > 1) { commentSubPageIndex--; if (commentSubPageIndex < 0) { mainPageIndex = (mainPageIndex - 1 + TOTAL_MAIN_PAGES) % TOTAL_MAIN_PAGES; const newSphereIdx = parseInt(infoPanelEl.dataset.sphereIndex, 10); /* このままだと新しい球のコメントに即座に変わらない */ const newCommentData = CUBE_COMMENTS[newSphereIdx] || DEFAULT_COMMENT_ARRAY_INFO; infoPanelEl.dataset.commentInfo = JSON.stringify(newCommentData); infoPanelEl.dataset.commentSubPageCount = newCommentData.text.length.toString(); infoPanelEl.dataset.activeLinkUrl = newCommentData.link || ""; commentSubPageIndex = Math.max(0, newCommentData.text.length - 1); } } else { mainPageIndex = (mainPageIndex - 1 + TOTAL_MAIN_PAGES) % TOTAL_MAIN_PAGES; commentSubPageIndex = 0; if (PAGES[mainPageIndex] === 'comment') { const newSphereIdx = parseInt(infoPanelEl.dataset.sphereIndex, 10); const newCommentData = CUBE_COMMENTS[newSphereIdx] || DEFAULT_COMMENT_ARRAY_INFO; infoPanelEl.dataset.commentInfo = JSON.stringify(newCommentData); infoPanelEl.dataset.commentSubPageCount = newCommentData.text.length.toString(); infoPanelEl.dataset.activeLinkUrl = newCommentData.link || ""; commentSubPageIndex = Math.max(0, newCommentData.text.length - 1); } else { infoPanelEl.dataset.activeLinkUrl = ""; } } infoPanelEl.dataset.currentPageIndex = mainPageIndex.toString(); infoPanelEl.dataset.commentSubPageIndex = commentSubPageIndex.toString(); updatePanelDisplay(); console.log("Prev button: mainPage=", mainPageIndex, "subPage=", commentSubPageIndex); });
nextButtonEl.addEventListener('click', function (event) { /* ... (省略) ... */ event.stopPropagation(); if (!infoPanelEl.getAttribute('visible')) return; let mainPageIndex = parseInt(infoPanelEl.dataset.currentPageIndex || '0', 10); let commentSubPageIndex = parseInt(infoPanelEl.dataset.commentSubPageIndex || '0', 10); const commentSubPageCount = parseInt(infoPanelEl.dataset.commentSubPageCount || '1', 10); if (PAGES[mainPageIndex] === 'comment' && commentSubPageCount > 1) { commentSubPageIndex++; if (commentSubPageIndex >= commentSubPageCount) { mainPageIndex = (mainPageIndex + 1) % TOTAL_MAIN_PAGES; commentSubPageIndex = 0; if (PAGES[mainPageIndex] === 'comment') { const newSphereIdx = parseInt(infoPanelEl.dataset.sphereIndex, 10); const newCommentData = CUBE_COMMENTS[newSphereIdx] || DEFAULT_COMMENT_ARRAY_INFO; infoPanelEl.dataset.commentInfo = JSON.stringify(newCommentData); infoPanelEl.dataset.commentSubPageCount = newCommentData.text.length.toString(); infoPanelEl.dataset.activeLinkUrl = newCommentData.link || ""; } else { infoPanelEl.dataset.activeLinkUrl = ""; } } } else { mainPageIndex = (mainPageIndex + 1) % TOTAL_MAIN_PAGES; commentSubPageIndex = 0; if (PAGES[mainPageIndex] === 'comment') { const newSphereIdx = parseInt(infoPanelEl.dataset.sphereIndex, 10); const newCommentData = CUBE_COMMENTS[newSphereIdx] || DEFAULT_COMMENT_ARRAY_INFO; infoPanelEl.dataset.commentInfo = JSON.stringify(newCommentData); infoPanelEl.dataset.commentSubPageCount = newCommentData.text.length.toString(); infoPanelEl.dataset.activeLinkUrl = newCommentData.link || ""; } else { infoPanelEl.dataset.activeLinkUrl = ""; } } infoPanelEl.dataset.currentPageIndex = mainPageIndex.toString(); infoPanelEl.dataset.commentSubPageIndex = commentSubPageIndex.toString(); updatePanelDisplay(); console.log("Next button: mainPage=", mainPageIndex, "subPage=", commentSubPageIndex); });
// --- ★★★ 閉じるボタンのクリック処理 (リンクURLデータ削除追加) ★★★ ---
closeButtonEl.addEventListener('click', function (event) {
event.stopPropagation();
infoPanelEl.setAttribute('visible', false);
delete infoPanelEl.dataset.sphereIndex; delete infoPanelEl.dataset.color; delete infoPanelEl.dataset.size;
delete infoPanelEl.dataset.currentPageIndex; delete infoPanelEl.dataset.commentInfo;
delete infoPanelEl.dataset.commentSubPageIndex; delete infoPanelEl.dataset.commentSubPageCount;
delete infoPanelEl.dataset.activeLinkUrl; // ★ リンクURLも削除
linkButtonEl.setAttribute('visible', false); // 念のためリンクボタンも非表示に
console.log("Close button clicked, panel hidden.");
});
// --- ★★★ リンクボタンのクリック処理を追加 ★★★ ---
linkButtonEl.addEventListener('click', function(event) {
event.stopPropagation();
const url = infoPanelEl.dataset.activeLinkUrl;
if (url) {
console.log("Link button clicked, opening URL:", url);
window.open(url, '_blank'); // 新しいタブでURLを開く
} else {
console.log("Link button clicked, but no URL found.");
}
});
// --- VRモードによるマウスカーソル表示制御 (変更なし) ---
sceneEl.addEventListener('enter-vr', function () { console.log("Entered VR mode"); if (mouseCursorEl) mouseCursorEl.setAttribute('visible', 'false'); });
sceneEl.addEventListener('exit-vr', function () { console.log("Exited VR mode"); if (mouseCursorEl) mouseCursorEl.setAttribute('visible', 'true'); });
// --- 右手コントローラーのトリガーイベントをリッスン (変更なし) ---
sceneEl.addEventListener('loaded', function() { rightHandEl = document.getElementById('rightHand'); if (rightHandEl) { rightHandEl.addEventListener('triggerdown', function (evt) { console.log('Right hand TRIGGER DOWN event!', evt); const raycasterComponent = rightHandEl.components.raycaster; if (raycasterComponent) { const intersectedEls = raycasterComponent.intersectedEls; if (intersectedEls.length > 0) { console.log('Trigger pressed while intersecting:', intersectedEls[0].tagName, intersectedEls[0].id || 'no id'); } else { console.log('Right Trigger pressed, but no intersection.'); } } }); rightHandEl.addEventListener('triggerup', function (evt) { console.log('Right hand TRIGGER UP event!', evt); }); } else { console.error("Could not find rightHand element to attach trigger listener."); } });
</script>
</a-scene>
</body>
</html>
a-farme-球に文字test43
├
<!DOCTYPE html>
<html>
<head>
<title>A-Frame - パネルテキストスタイル変更</title>
<script src="https://aframe.io/releases/1.7.0/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-look-at-component@0.8.0/dist/aframe-look-at-component.min.js"></script>
<script src="https://unpkg.com/aframe-troika-text/dist/aframe-troika-text.min.js"></script>
<script>
// --- プレイヤー移動制御用カスタムコンポーネント ('camera-relative-controls') ---
// (変更なし - 省略)
AFRAME.registerComponent('camera-relative-controls', { schema: { targetSpeed: { type: 'number', default: 5 }, acceleration: { type: 'number', default: 10 }, damping: { type: 'number', default: 8 }, brakingDeceleration: { type: 'number', default: 20 }, enabled: { type: 'boolean', default: true } }, init: function () { this.keys = {}; this.thumbstickInput = { x: 0, y: 0 }; this.currentVelocity = new THREE.Vector3(); this.ZERO_VECTOR = new THREE.Vector3(); this.cameraDirection = new THREE.Vector3(); this.cameraRight = new THREE.Vector3(); this.moveDirection = new THREE.Vector3(); this.desiredVelocity = new THREE.Vector3(); this.cameraWorldQuaternion = new THREE.Quaternion(); this.cameraEl = this.el.querySelector('[camera]'); this.isReady = false; if (!this.cameraEl) { console.error('camera-relative-controls: カメラエンティティが見つかりません。'); } this.el.sceneEl.addEventListener('loaded', () => { this.leftHand = document.getElementById('leftHand'); if (this.leftHand) { this.leftHand.addEventListener('thumbstickmoved', this.onThumbstickMoved.bind(this)); } else { console.warn("camera-relative-controls: 左手コントローラー(#leftHand)が見つかりません。"); } }); this.onKeyDown = this.onKeyDown.bind(this); this.onKeyUp = this.onKeyUp.bind(this); window.addEventListener('keydown', this.onKeyDown); window.addEventListener('keyup', this.onKeyUp); }, remove: function () { window.removeEventListener('keydown', this.onKeyDown); window.removeEventListener('keyup', this.onKeyUp); if (this.leftHand) { try { this.leftHand.removeEventListener('thumbstickmoved', this.onThumbstickMoved.bind(this)); } catch(e) { console.warn("camera-relative-controls: スティックリスナー解除失敗の可能性あり"); } } }, onThumbstickMoved: function (evt) { this.thumbstickInput.x = evt.detail.x; this.thumbstickInput.y = evt.detail.y; }, tick: function (time, timeDelta) { if (!this.data.enabled) return; if (!this.isReady) { if (this.cameraEl && this.cameraEl.object3D && this.cameraEl.object3D.matrixWorld) { this.isReady = true; } else { if (!this.cameraEl) { this.cameraEl = this.el.querySelector('[camera]'); } return; } } if (!this.cameraEl || !this.cameraEl.object3D) { return; } const el = this.el; const data = this.data; const position = el.object3D.position; const dt = timeDelta / 1000; this.cameraEl.object3D.getWorldQuaternion(this.cameraWorldQuaternion); this.cameraDirection.set(0, 0, -1).applyQuaternion(this.cameraWorldQuaternion); if (this.cameraDirection.lengthSq() > 0.0001) this.cameraDirection.normalize(); this.cameraRight.set(1, 0, 0).applyQuaternion(this.cameraWorldQuaternion); this.cameraRight.y = 0; if (this.cameraRight.lengthSq() > 0.0001) this.cameraRight.normalize(); this.moveDirection.set(0, 0, 0); if (this.keys['KeyW'] || this.keys['ArrowUp']) { this.moveDirection.add(this.cameraDirection); } if (this.keys['KeyS'] || this.keys['ArrowDown']) { this.moveDirection.sub(this.cameraDirection); } if (this.keys['KeyA'] || this.keys['ArrowLeft']) { this.moveDirection.sub(this.cameraRight); } if (this.keys['KeyD'] || this.keys['ArrowRight']) { this.moveDirection.add(this.cameraRight); } if (Math.abs(this.thumbstickInput.y) > 0.1) { const forwardBackward = this.cameraDirection.clone().multiplyScalar(-this.thumbstickInput.y); this.moveDirection.add(forwardBackward); } if (Math.abs(this.thumbstickInput.x) > 0.1) { const leftRight = this.cameraRight.clone().multiplyScalar(this.thumbstickInput.x); this.moveDirection.add(leftRight); } const isInputActive = this.moveDirection.lengthSq() > 0.0001; if (isInputActive) { this.moveDirection.normalize(); } let lerpFactor = data.damping; const isCurrentlyMoving = this.currentVelocity.lengthSq() > 0.01; if (isInputActive) { let isOpposingInput = false; if (isCurrentlyMoving) { const dotProduct = this.currentVelocity.dot(this.moveDirection); if (dotProduct < -0.1) { isOpposingInput = true; } } if (isOpposingInput) { this.desiredVelocity.copy(this.ZERO_VECTOR); lerpFactor = data.brakingDeceleration; } else { this.desiredVelocity.copy(this.moveDirection).multiplyScalar(data.targetSpeed); lerpFactor = data.acceleration; } } else { this.desiredVelocity.copy(this.ZERO_VECTOR); lerpFactor = data.damping; } const effectiveLerpFactor = 1.0 - Math.exp(-lerpFactor * dt); this.currentVelocity.lerp(this.desiredVelocity, effectiveLerpFactor); if (this.currentVelocity.lengthSq() < 0.0001) { this.currentVelocity.copy(this.ZERO_VECTOR); } if (this.currentVelocity.lengthSq() > 0) { const deltaPosition = this.currentVelocity.clone().multiplyScalar(dt); position.add(deltaPosition); } }, onKeyDown: function (event) { if (!this.data.enabled) { return; } if (['KeyW', 'ArrowUp', 'KeyS', 'ArrowDown', 'KeyA', 'ArrowLeft', 'KeyD', 'ArrowRight'].includes(event.code)) { this.keys[event.code] = true; } }, onKeyUp: function (event) { if (this.keys[event.code] !== undefined) { delete this.keys[event.code]; } } });
// --- 立方体をランダムに回転させるカスタムコンポーネント ('random-rotate') ---
// (変更なし - 省略)
AFRAME.registerComponent('random-rotate', { schema: { maxSpeed: { type: 'number', default: 5 } }, init: function () { this.axis = new THREE.Vector3(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5).normalize(); const speed = ((Math.random() * 0.8) + 0.2) * this.data.maxSpeed * (Math.random() < 0.5 ? 1 : -1); this.speedRad = THREE.MathUtils.degToRad(speed); this.deltaRotationQuaternion = new THREE.Quaternion(); }, tick: function (time, timeDelta) { const dt = timeDelta / 1000; const angle = this.speedRad * dt; this.deltaRotationQuaternion.setFromAxisAngle(this.axis, angle); this.el.object3D.quaternion.multiplyQuaternions(this.deltaRotationQuaternion, this.el.object3D.quaternion); } });
</script>
</head>
<body>
<a-scene id="myScene" background="color: #000000" vr-mode-ui="enabled: true">
<a-entity id="rig" position="0 0 5"
camera-relative-controls="targetSpeed: 250; acceleration: 3; damping: 5; brakingDeceleration: 1;">
<a-entity id="camera" camera="far: 20000;" look-controls position="0 1.6 0">
<a-entity id="mouseCursor" cursor="rayOrigin: mouse; fuse: false;" raycaster="objects: .clickableObject, .clickableButton; far: 3000;" position="0 0 -1" geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03;" material="color: black; shader: flat; opacity: 0.7;"> <a-animation begin="click" easing="ease-in" attribute="scale" fill="backwards" from="0.1 0.1 0.1" to="1 1 1" dur="150"></a-animation> </a-entity>
</a-entity>
<a-entity id="leftHand" oculus-touch-controls="hand: left; model: true;"></a-entity>
<a-entity id="rightHand" oculus-touch-controls="hand: right; model: true;" raycaster="objects: .clickableObject, .clickableButton; far: 3000; enabled: true;" laser-controls="hand: right; model: false; lineColor: white; lineOpacity: 0.75" ></a-entity>
</a-entity>
<a-entity light="type: ambient; color: #444"></a-entity>
<a-entity light="type: directional; color: #FFF; intensity: 0.8" position="-1 1.5 1"></a-entity>
<a-entity light="type: directional; color: #AAA; intensity: 0.4" position="1 1 -1"></a-entity>
<a-entity id="infoPanel" visible="false" position="0 -1000 0" look-at="[camera]">
<a-plane id="panelBackground" width="50" height="24" color="#333" opacity="0.9" side="double"></a-plane>
<a-entity id="panelText" troika-text="value: Placeholder; color: white; fontSize: 0.72; maxWidth: 46; align: center; anchorX: center; anchorY: middle; baseline: middle;" position="0 0 0.05"> </a-entity>
<a-cone id="prevButton" class="clickableButton" position="-20.0 0 0.1" rotation="0 0 90" radius-bottom="1.2" radius-top="0" height="2.0" material="color: #CCC; shader: flat; opacity: 0.8;"> </a-cone>
<a-cone id="nextButton" class="clickableButton" position="20.0 0 0.1" rotation="0 0 -90" radius-bottom="1.2" radius-top="0" height="2.0" material="color: #CCC; shader: flat; opacity: 0.8;"> </a-cone>
<a-sphere id="closeButton" class="clickableButton" position="24 11 0.1" radius="1.5" color="red" shader="flat"> </a-sphere>
</a-entity>
<script>
// --- グローバル変数とDOM要素の取得 ---
const sceneEl = document.getElementById('myScene');
const infoPanelEl = document.getElementById('infoPanel');
const panelTextEl = document.getElementById('panelText');
const cameraEl = document.getElementById('camera');
const prevButtonEl = document.getElementById('prevButton');
const nextButtonEl = document.getElementById('nextButton');
const closeButtonEl = document.getElementById('closeButton');
const mouseCursorEl = document.getElementById('mouseCursor');
let rightHandEl = null;
// ★★★ パネルの表示オフセット距離 (デフォルト値を5に変更) ★★★
const PANEL_OFFSET_FROM_OBJECT = 5.0;
// ★★★ ページごとのテキストスタイル定義 ★★★
const BASE_TEXT_STYLE = {
maxWidth: 46, align: 'center', anchorX: 'center', anchorY: 'middle', baseline: 'middle'
};
const PAGE_TEXT_STYLES = {
'index': { ...BASE_TEXT_STYLE, fontSize: 0.72, color: 'white' },
'color': { ...BASE_TEXT_STYLE, fontSize: 0.65, color: '#A0F0A0' }, // 少し彩度を落として見やすく
'size': { ...BASE_TEXT_STYLE, fontSize: 0.80, color: '#FFEC8B' }, // 少し彩度を落として見やすく
'comment': { ...BASE_TEXT_STYLE, fontSize: 0.70, color: '#ADD8E6' }
};
// ★★★ ここまでスタイル定義 ★★★
// --- 立方体ごとのコメントデータ (変更なし) ---
const CUBE_COMMENTS = { 1: ["最初の立方体だ!", "何か秘密が隠されているかもしれない…"], 5: ["これは5番目の特別な立方体。", "長いコメントもこのように複数ページにわたって表示できます。", "素晴らしい発見だ!"], 10: ["ようこそ、宇宙の果てへ。"], 25: ["折り返し地点です。"] };
const DEFAULT_COMMENT_ARRAY = ["コメントはありません"];
// --- 定数定義 (変更なし) ---
const numSpheres = 60; const spread = 2000; const PAGES = ['index', 'color', 'size', 'comment']; const TOTAL_MAIN_PAGES = PAGES.length;
const targetWorldPosition = new THREE.Vector3(); const cameraWorldPosition = new THREE.Vector3(); const direction = new THREE.Vector3(); const panelPosition = new THREE.Vector3();
// --- 立方体生成ループ (変更なし) ---
for (let i = 0; i < numSpheres; i++) { const cubeEl = document.createElement('a-box'); const side = Math.random() * 10.0 + 0.5; const x = (Math.random() - 0.5) * spread; const y = Math.random() * (spread / 2) + side / 2; const z = (Math.random() - 0.5) * spread; const color = `hsl(${Math.random() * 360}, 50%, 75%)`; const sphereIndex = i + 1; cubeEl.setAttribute('width', side); cubeEl.setAttribute('height', side); cubeEl.setAttribute('depth', side); cubeEl.setAttribute('color', color); cubeEl.setAttribute('position', { x: x, y: y, z: z }); cubeEl.classList.add('clickableObject'); cubeEl.dataset.sphereIndex = sphereIndex; cubeEl.dataset.color = color; cubeEl.dataset.size = side.toFixed(2); cubeEl.setAttribute('random-rotate', {maxSpeed: 5}); cubeEl.addEventListener('click', handleSphereClick); sceneEl.appendChild(cubeEl); }
// --- ★★★ 情報パネルの表示更新関数 (テキストスタイル適用) ★★★ ---
function updatePanelDisplay() {
if (!infoPanelEl.dataset.sphereIndex) return;
const index = parseInt(infoPanelEl.dataset.sphereIndex || '0', 10);
const color = infoPanelEl.dataset.color || 'N/A';
const size = infoPanelEl.dataset.size || 'N/A';
const commentsArray = JSON.parse(infoPanelEl.dataset.comments || JSON.stringify(DEFAULT_COMMENT_ARRAY));
const commentSubPageCount = parseInt(infoPanelEl.dataset.commentSubPageCount || '1', 10);
const commentSubPageIndex = parseInt(infoPanelEl.dataset.commentSubPageIndex || '0', 10);
const mainPageIndex = parseInt(infoPanelEl.dataset.currentPageIndex || '0', 10);
let displayText = '';
const pageType = PAGES[mainPageIndex];
let pageIndicator = `(${mainPageIndex + 1}/${TOTAL_MAIN_PAGES})`;
const currentStyle = PAGE_TEXT_STYLES[pageType] || PAGE_TEXT_STYLES['index']; // スタイル取得
if (pageType === 'index') { displayText = `立方体: ${index}`; }
else if (pageType === 'color') { displayText = `色: ${color}`; }
else if (pageType === 'size') { displayText = `サイズ: ${size}`; }
else if (pageType === 'comment') {
displayText = `コメント:\n${commentsArray[commentSubPageIndex]}`;
pageIndicator = `(${mainPageIndex + 1}/${TOTAL_MAIN_PAGES} - コメント ${commentSubPageIndex + 1}/${commentSubPageCount})`;
}
const finalDisplayText = `${pageIndicator}\n${displayText}`;
// troika-text属性をオブジェクトで設定(スタイルも含む)
panelTextEl.setAttribute('troika-text', {
value: finalDisplayText,
color: currentStyle.color,
fontSize: currentStyle.fontSize,
maxWidth: currentStyle.maxWidth,
align: currentStyle.align,
anchorX: currentStyle.anchorX,
anchorY: currentStyle.anchorY,
baseline: currentStyle.baseline
});
}
// --- ★★★ 立方体クリック時の処理 (PANEL_OFFSET_FROM_OBJECT を使用) ★★★ ---
function handleSphereClick(event) {
event.stopPropagation();
console.log("--- handleSphereClick triggered --- Target:", event.target.id || event.target.tagName);
const clickedCube = event.target;
if (!clickedCube.dataset.sphereIndex || !clickedCube.dataset.color || !clickedCube.dataset.size) {
console.error("Cube data missing from dataset!", clickedCube.dataset); return;
}
console.log("Cube data found:", clickedCube.dataset);
infoPanelEl.dataset.sphereIndex = clickedCube.dataset.sphereIndex;
infoPanelEl.dataset.color = clickedCube.dataset.color;
infoPanelEl.dataset.size = clickedCube.dataset.size;
infoPanelEl.dataset.currentPageIndex = '0';
const sphereIdx = parseInt(clickedCube.dataset.sphereIndex, 10);
const commentsForThisCube = CUBE_COMMENTS[sphereIdx] || DEFAULT_COMMENT_ARRAY;
infoPanelEl.dataset.comments = JSON.stringify(commentsForThisCube);
infoPanelEl.dataset.commentSubPageCount = commentsForThisCube.length.toString();
infoPanelEl.dataset.commentSubPageIndex = '0';
console.log("Data (including comments) stored in panel dataset.");
try { updatePanelDisplay(); console.log("updatePanelDisplay completed."); }
catch (e) { console.error("Error during updatePanelDisplay:", e); return; }
try {
clickedCube.object3D.getWorldPosition(targetWorldPosition);
cameraEl.object3D.getWorldPosition(cameraWorldPosition);
const cubeSide = parseFloat(clickedCube.dataset.size || 0);
// パネルオフセット距離に新しい変数を使用
const offsetDistance = cubeSide / 2 + PANEL_OFFSET_FROM_OBJECT;
direction.subVectors(cameraWorldPosition, targetWorldPosition).normalize();
panelPosition.copy(targetWorldPosition).addScaledVector(direction, offsetDistance);
infoPanelEl.object3D.position.copy(panelPosition);
console.log("Panel position calculated and applied.");
}
catch(e) { console.error("Error during position calculation:", e); return; }
infoPanelEl.setAttribute('visible', true);
console.log("Panel visibility set to true. --- handleSphereClick end ---");
}
// --- パネルのボタンクリック処理 (コメント複数ページ対応) (変更なし) ---
prevButtonEl.addEventListener('click', function (event) { event.stopPropagation(); if (!infoPanelEl.getAttribute('visible')) return; let mainPageIndex = parseInt(infoPanelEl.dataset.currentPageIndex || '0', 10); let commentSubPageIndex = parseInt(infoPanelEl.dataset.commentSubPageIndex || '0', 10); const commentSubPageCount = parseInt(infoPanelEl.dataset.commentSubPageCount || '1', 10); if (PAGES[mainPageIndex] === 'comment' && commentSubPageCount > 1) { commentSubPageIndex--; if (commentSubPageIndex < 0) { mainPageIndex = (mainPageIndex - 1 + TOTAL_MAIN_PAGES) % TOTAL_MAIN_PAGES; const newCommentsArray = JSON.parse(infoPanelEl.dataset.comments || JSON.stringify(DEFAULT_COMMENT_ARRAY)); commentSubPageIndex = Math.max(0, newCommentsArray.length - 1); } } else { mainPageIndex = (mainPageIndex - 1 + TOTAL_MAIN_PAGES) % TOTAL_MAIN_PAGES; commentSubPageIndex = 0; } infoPanelEl.dataset.currentPageIndex = mainPageIndex.toString(); infoPanelEl.dataset.commentSubPageIndex = commentSubPageIndex.toString(); updatePanelDisplay(); console.log("Prev button: mainPage=", mainPageIndex, "subPage=", commentSubPageIndex); });
nextButtonEl.addEventListener('click', function (event) { event.stopPropagation(); if (!infoPanelEl.getAttribute('visible')) return; let mainPageIndex = parseInt(infoPanelEl.dataset.currentPageIndex || '0', 10); let commentSubPageIndex = parseInt(infoPanelEl.dataset.commentSubPageIndex || '0', 10); const commentSubPageCount = parseInt(infoPanelEl.dataset.commentSubPageCount || '1', 10); if (PAGES[mainPageIndex] === 'comment' && commentSubPageCount > 1) { commentSubPageIndex++; if (commentSubPageIndex >= commentSubPageCount) { mainPageIndex = (mainPageIndex + 1) % TOTAL_MAIN_PAGES; commentSubPageIndex = 0; } } else { mainPageIndex = (mainPageIndex + 1) % TOTAL_MAIN_PAGES; commentSubPageIndex = 0; } infoPanelEl.dataset.currentPageIndex = mainPageIndex.toString(); infoPanelEl.dataset.commentSubPageIndex = commentSubPageIndex.toString(); updatePanelDisplay(); console.log("Next button: mainPage=", mainPageIndex, "subPage=", commentSubPageIndex); });
// --- 閉じるボタンのクリック処理 (コメントデータ削除追加) (変更なし) ---
closeButtonEl.addEventListener('click', function (event) { event.stopPropagation(); infoPanelEl.setAttribute('visible', false); delete infoPanelEl.dataset.sphereIndex; delete infoPanelEl.dataset.color; delete infoPanelEl.dataset.size; delete infoPanelEl.dataset.currentPageIndex; delete infoPanelEl.dataset.comments; delete infoPanelEl.dataset.commentSubPageIndex; delete infoPanelEl.dataset.commentSubPageCount; console.log("Close button clicked, panel hidden."); });
// --- VRモードによるマウスカーソル表示制御 (変更なし) ---
sceneEl.addEventListener('enter-vr', function () { console.log("Entered VR mode"); if (mouseCursorEl) mouseCursorEl.setAttribute('visible', 'false'); });
sceneEl.addEventListener('exit-vr', function () { console.log("Exited VR mode"); if (mouseCursorEl) mouseCursorEl.setAttribute('visible', 'true'); });
// --- 右手コントローラーのトリガーイベントをリッスン (変更なし) ---
sceneEl.addEventListener('loaded', function() { rightHandEl = document.getElementById('rightHand'); if (rightHandEl) { rightHandEl.addEventListener('triggerdown', function (evt) { console.log('Right hand TRIGGER DOWN event!', evt); const raycasterComponent = rightHandEl.components.raycaster; if (raycasterComponent) { const intersectedEls = raycasterComponent.intersectedEls; if (intersectedEls.length > 0) { console.log('Trigger pressed while intersecting:', intersectedEls[0].tagName, intersectedEls[0].id || 'no id'); } else { console.log('Right Trigger pressed, but no intersection.'); } } }); rightHandEl.addEventListener('triggerup', function (evt) { console.log('Right hand TRIGGER UP event!', evt); }); } else { console.error("Could not find rightHand element to attach trigger listener."); } });
</script>
</a-scene>
</body>
</html>
a-farme-球に文字test41
├
afarme-test
├
C#のtest
│├
ページのソース取得は var html = driver.PageSource; の1行
これを
// Cromeで、読んだURLを開く
driver.Navigate().GoToUrl(str);
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(d => d.FindElement(By.TagName("body"))); // bodyタグが読み込まれるのを待機
// body要素全体の表示テキストを取得
string visibleText = driver.FindElement(By.TagName("body")).Text;
// 取得したテキストをファイルに保存 (UTF-8で保存する例)
File.WriteAllText("out2.txt", visibleText, Encoding.UTF8);
driver.Quit();
ということでbodyの文字を取得である程度は文字を得られるはず
C#のソースをTEXTに
│├
{
// IntelliSense を使用して利用可能な属性を学べます。
// 既存の属性の説明をホバーして表示します。
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{ // ← オブジェクトの開始
"name": "C#: test8",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}/bin/Debug/net8.0/test8.dll" // ← 末尾のコンマを削除
} // ← オブジェクトの終了
]
}
launch.json 間違い修正
│└
//test6からソース取得を削ってtest7のテキスト取得だけにした物 クリップボードからテキストにするバッチファイルも出す仕様にした。
using System;
using System.IO;
using System.Threading;
using System.Diagnostics;// 外部ファイル実行に必要
using System.Text;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Interactions;
using OpenQA.Selenium.Support.UI;// WebDriverWaitを使うには必要
IWebDriver driver = new ChromeDriver();
// コードページ エンコーディング プロバイダーを登録
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);// Shift-JIS や EUC-JP使う場合に必要
//自分自身の実行ファイルのパスを取得し、作業ディレクトリを移動する
string appPath = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
Directory.SetCurrentDirectory(appPath);
Console.WriteLine(appPath);
//URLの書いてあるread.txtを読む
StreamReader sr = new StreamReader("read.txt", Encoding.UTF8);
// StreamReader sr = new StreamReader("read.txt", Encoding.GetEncoding("Shift_JIS"));
string str = sr.ReadToEnd();
sr.Close();
string huga = "";
System.Console.WriteLine(huga);System.Console.WriteLine(huga);System.Console.WriteLine(huga);
// Cromeで、読んだURLを開く
driver.Navigate().GoToUrl(str);
//driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(d => d.FindElement(By.TagName("body"))); // bodyタグが読み込まれるのを待機
Thread.Sleep(1000);//3秒待つ
// Seleniumのkeyでキー操作
driver.FindElement(By.TagName("html")).SendKeys(OpenQA.Selenium.Keys.LeftControl + "a" );Thread.Sleep(500);
driver.FindElement(By.TagName("html")).SendKeys(OpenQA.Selenium.Keys.LeftControl + "c" );
Thread.Sleep(2000); // 2秒待機
// バッチファイルでクリップボードの内容をテキストにする
//string outc = "powershell -Command \"Get-ClipBoard\" > out2.txt";//バッチを作る
string outc = "powershell -Command \"Get-ClipBoard | Out-File -FilePath out2.txt -Encoding utf8\""; //バッチを作る
File.WriteAllText("txtput.bat", outc);
Thread.Sleep(500);
var startInfo = new ProcessStartInfo("txtput.bat")
{WindowStyle = ProcessWindowStyle.Hidden}; // 非表示で実行
Process.Start(startInfo)?.WaitForExit();
driver.Quit();
test8xx-
├
ファイルリストアップ
├
はい、Python を使って Blogger API 経由で投稿を作成することは可能です。Google API Client Library for Python を利用するのが一般的です。
以下に、大まかな手順と考慮すべき点を説明します。
**主な手順**
1. **Google API Console でプロジェクトを作成し、Blogger API を有効にする:**
* Google API Console ([https://console.developers.google.com/](https://console.developers.google.com/)) にアクセスします。
* 新しいプロジェクトを作成するか、既存のプロジェクトを選択します。
* 「APIとサービスを有効化」から Blogger API v3 を検索し、有効にします。
2. **認証情報を作成する:**
* Blogger API を使用するには、認証情報が必要です。通常、OAuth 2.0 を使用します。
* API Console の「認証情報」ページで、OAuth 2.0 クライアント ID を作成します。アプリケーションの種類に応じて、「ウェブ アプリケーション」や「デスクトップ アプリ」などを選択します。
* 作成されたクライアント ID とクライアント シークレットを安全に保管してください。
* リダイレクト URI も適切に設定する必要があります。
3. **Google API Client Library for Python をインストールする:**
ターミナルまたはコマンドプロンプトで以下のコマンドを実行します。
```bash
pip install google-api-python-client google-auth-httplib2 google-auth-oauthlib
```
4. **Python コードで認証と API 呼び出しを実装する:**
* **認証:**
* `google-auth-oauthlib` ライブラリを使用して、ユーザーに認証を求め、アクセストークンを取得します。このプロセスでは、ユーザーがブラウザでGoogleアカウントにログインし、アプリケーションに権限を付与する必要があります。
* 取得したアクセストークンは、API リクエストの際に使用します。必要に応じてリフレッシュトークンも保存し、アクセストークンの有効期限が切れた際に再取得できるようにします。
* **Blogger API サービスの構築:**
* `googleapiclient.discovery.build` 関数を使用して、Blogger API のサービスオブジェクトを構築します。
* **投稿の作成:**
* サービスオブジェクトの `posts().insert()` メソッドを呼び出して新しい投稿を作成します。
* リクエストボディには、投稿のタイトル、コンテンツ(HTML形式)、ラベル(オプション)などを含めます。
* `blogId` パラメータで、投稿先のブログの ID を指定する必要があります。ブログ ID は、Blogger の管理画面の URL などから確認できます。
**コードの基本的な流れ(概念的な例)**
```python
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
import pickle
import os.path
# OAuth 2.0 のスコープ (Blogger API への書き込み権限)
SCOPES = ['https://www.googleapis.com/auth/blogger']
# 認証情報ファイルのパス (API Console からダウンロードした JSON ファイル)
CLIENT_SECRETS_FILE = 'client_secret.json' # ご自身のファイル名に置き換えてください
# トークン保存ファイルのパス
TOKEN_PICKLE_FILE = 'token.pickle'
def get_credentials():
"""OAuth 2.0 認証情報を取得または更新する"""
creds = None
# 既に保存されたトークンがあるか確認
if os.path.exists(TOKEN_PICKLE_FILE):
with open(TOKEN_PICKLE_FILE, 'rb') as token:
creds = pickle.load(token)
# 有効な認証情報がない場合、または期限切れの場合は、新しく取得
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
CLIENT_SECRETS_FILE, SCOPES)
# ローカルサーバーを起動して認証フローを実行する場合
# creds = flow.run_local_server(port=0)
# コンソールベースで認証フローを実行する場合
creds = flow.run_console()
# 取得した認証情報を保存
with open(TOKEN_PICKLE_FILE, 'wb') as token:
pickle.dump(creds, token)
return creds
def main():
"""Blogger API を使用して投稿を作成するメイン関数"""
creds = get_credentials()
service = build('blogger', 'v3', credentials=creds)
# ブログID (Blogger の管理画面 URL などから確認)
blog_id = 'YOUR_BLOG_ID' # ご自身のブログIDに置き換えてください
# 投稿内容
post_body = {
"title": "Pythonからのテスト投稿",
"content": "<p>これはPythonスクリプトからBlogger APIを使って投稿されたテスト記事です。</p>",
# "labels": ["Python", "API", "Test"] # オプションでラベルも指定可能
}
try:
# 投稿を作成 (isDraft=False で公開、True で下書き)
request = service.posts().insert(blogId=blog_id, body=post_body, isDraft=False)
post = request.execute()
print(f"投稿が作成されました。投稿ID: {post['id']}")
print(f"投稿URL: {post['url']}")
except Exception as e:
print(f"エラーが発生しました: {e}")
if __name__ == '__main__':
main()
```
**重要な注意点:**
* **エラーハンドリング:** API 呼び出しは失敗する可能性があるため、適切に `try...except` ブロックを使用してエラーを処理してください。
* **セキュリティ:** クライアントシークレットやトークンなどの機密情報は、安全に管理してください。コードに直接ハードコーディングするのではなく、環境変数や設定ファイルから読み込むことを検討しましょう。
* **API の制限:** Blogger API には、リクエスト数などの制限がある場合があります。ドキュメントを確認し、制限を超えないように注意してください。
* **ブログ ID:** 正しいブログ ID を指定する必要があります。これは、Blogger のダッシュボードの URL などで確認できます(通常は数字の羅列です)。
* **コンテンツの形式:** `content` フィールドには HTML 形式の文字列を指定します。
* **下書きとしての投稿:** `insert()` メソッドの `isDraft` パラメータを `True` に設定すると、投稿を下書きとして保存できます。公開する場合は `False` にします。
**参考情報:**
* **Blogger API v3 ドキュメント:** [https://developers.google.com/blogger/docs/3.0/reference](https://developers.google.com/blogger/docs/3.0/reference)
* **Google API Client Library for Python:** [https://github.com/googleapis/google-api-python-client](https://github.com/googleapis/google-api-python-client)
* **Python Quickstart (Google API):** [https://developers.google.com/docs/api/quickstart/python](https://developers.google.com/docs/api/quickstart/python) (特定の API 向けですが、認証フローの参考になります)
この情報が、Python を使った Blogger への投稿作成の助けになれば幸いです。もし具体的なコードで詰まっている点があれば、遠慮なくご質問ください。
ブロガーに投稿
├
geminiの2.5pro DSで調査しても詳しくは不明 カテゴリ親子関係についてはWEB上で手動設定以外なく、XMLRPCで設定はできない。
ChatGPT
ログイン
新規登録
あなた:
perl の Xmlprc
ChatGPT:
Perl で XML-RPC を使用する場合、XML::RPC モジュールを使うことが一般的です。このモジュールは、XML-RPC プロトコルを使ってリモートの Web サービスと通信するためのライブラリです。
以下は、XML::RPC モジュールを使って XML-RPC リクエストを送信する基本的な例です。
1. 必要なモジュールのインストール
まず、XML::RPC モジュールを CPAN を使ってインストールします。
bash
コピーする
cpan install XML::RPC
2. 基本的な XML-RPC リクエストの例
以下は、XML-RPC サーバーにリクエストを送信し、レスポンスを受け取る Perl のコード例です。
perl
コピーする
use XML::RPC;
# サーバーの URL(例: http://example.com/RPC2)
my $url = 'http://example.com/RPC2';
# XML-RPC クライアントの作成
my $rpc = XML::RPC->new($url);
# メソッドの呼び出しと引数
my $method = 'example.method'; # 呼び出すメソッド名
my @params = ('param1', 'param2'); # メソッドの引数
# リクエストの送信とレスポンスの取得
my $response = $rpc->call($method, @params);
# レスポンスの処理
if ($response) {
print "レスポンス: ", $response, "\n";
} else {
print "エラー: ", $rpc->status, "\n";
}
3. エラーハンドリング
XML::RPC では、通信エラーやレスポンスエラーを適切に処理するために、エラーハンドリングを行うことが重要です。上記の例で示したように、$rpc->status でエラーメッセージを確認できます。
4. XML-RPC サーバーへの POST リクエスト
XML-RPC サーバーに対して POST リクエストを送信する必要がある場合もあります。この場合、XML::RPC は内部で自動的に HTTP リクエストを作成しますので、ユーザーが直接 HTTP リクエストを作成する必要はありません。
まとめ
このように、Perl で XML-RPC を使うには XML::RPC モジュールを活用することで、簡単にリモートサーバーと通信できます。呼び出したいメソッドとその引数を指定して、XML-RPC リクエストを送信し、レスポンスを受け取ることができます。
もし、さらに詳しい使い方や特定の要件があれば、教えてください!
あなた:
FC2ブログに XML-RPCで投稿したい
ChatGPT:
FC2ブログに XML-RPC を使って投稿するためには、FC2のブログの XML-RPC インターフェースを利用する方法があります。FC2ブログは XML-RPC をサポートしており、これを使用して自動的に記事を投稿したり、管理したりすることができます。
必要な情報
まず、FC2ブログに投稿するために必要な情報は以下の通りです:
XML-RPC エンドポイント URL: FC2ブログの場合、http://xmlrpc.fc2.com が基本のエンドポイントです。
ユーザー名 (ID): FC2ブログのログインID。
パスワード: FC2ブログのログインパスワード。
XML-RPC メソッド
FC2ブログの XML-RPC インターフェースにはいくつかのメソッドがありますが、投稿を行うためには metaWeblog.newPost メソッドを使用します。
必要なモジュール
Perl で XML-RPC を使用するためには、先ほども言及した通り XML::RPC モジュールが便利です。
1. モジュールのインストール
まず、Perl の環境に XML::RPC をインストールします。
bash
コピーする
cpan install XML::RPC
2. FC2ブログに投稿する Perl スクリプト
以下の Perl スクリプトを使って、FC2ブログに XML-RPC 経由で記事を投稿できます。
perl
コピーする
use XML::RPC;
use strict;
# FC2ブログのXML-RPCサーバーURL
my $url = 'http://xmlrpc.fc2.com';
# ユーザー名(FC2ブログのID)
my $username = 'your_username';
# パスワード(FC2ブログのパスワード)
my $password = 'your_password';
# 投稿のタイトルと内容
my $title = 'この記事のタイトル';
my $content = 'この記事の内容です。';
# 記事を公開するかどうか(公開する場合は1、下書きにする場合は0)
my $publish = 1;
# XML-RPC クライアントの作成
my $rpc = XML::RPC->new($url);
# FC2ブログの XML-RPC メソッドを呼び出し
# metaWeblog.newPost の引数は次の通り:
# 1. ブログID(ユーザー名)
# 2. パスワード
# 3. 投稿内容(タイトル、内容、公開設定)
my $response = $rpc->call('metaWeblog.newPost', $username, $password, {
title => $title,
description => $content,
categories => ['default'], # カテゴリの指定(必要に応じて変更)
}, $publish);
# 結果を表示
if ($response) {
print "記事の投稿に成功しました。\n";
print "投稿ID: ", $response, "\n";
} else {
print "記事の投稿に失敗しました。\n";
print "エラー: ", $rpc->status, "\n";
}
スクリプトの説明
URL: http://xmlrpc.fc2.com は FC2 の XML-RPC サーバーのエンドポイントです。
metaWeblog.newPost メソッド: これを使って新しい記事を投稿します。引数としてブログID、パスワード、投稿する内容(タイトル、内容、カテゴリ)、および公開設定(1: 公開, 0: 下書き)を渡します。
記事の内容とタイトル: $title と $content に投稿する記事のタイトルと内容を設定します。
レスポンス: 投稿が成功すると、投稿IDが返されます。失敗した場合はエラーメッセージを表示します。
3. 実行
このスクリプトを実行すると、FC2ブログに指定したタイトルと内容で投稿されます。投稿が成功すれば、その投稿IDも表示されます。
追加オプション
カテゴリの指定: categories => ['default'] の部分で、投稿するカテゴリを指定できます。カテゴリはブログ側であらかじめ作成しておく必要があります。
記事の公開設定: $publish = 1; を 0 に変更すると、記事は公開されずに下書きとして保存されます。
注意点
パスワードが正しいこと、FC2ブログのアカウントが有効であることを確認してください。
スクリプト内の your_username と your_password を実際の FC2 アカウントの情報に置き換えてください。
これで、XML-RPC 経由で FC2ブログに投稿する準備が整いました!
添付
検索
推論
Voice
ChatGPT の回答は必ずしも正しいとは限りません。重要な情報は確認するようにしてください。
?
FC2ブログに XML-RPCで投稿したい カテゴリについて書かれている
├
ブラウザのURL欄にJavaScriptのコードを直接入力して実行することで、ページに特殊な効果を与えるという試みは、過去にはよく見られました。しかし、おっしゃる通り、セキュリティ上の懸念から、現代の多くのブラウザではこのようなJavaScriptの実行は大幅に制限されています。特に、URL欄に `javascript:` で始まるコードをペーストして実行しようとすると、ブラウザが `javascript:` の部分を自動的に削除したり、実行をブロックしたりすることが一般的です。
それでも、完全に不可能になったわけではなく、状況によっては動作するものや、ブックマークレットという形でなら同様の機能を実現できる場合があります。
以下に、過去に知られていた、あるいはブックマークレットとして応用できる可能性のあるJavaScriptのアイデアと、それらが現代のブラウザでどのように扱われるかについて説明します。
**注意:以下のコードを試す場合は、自己責任でお願いします。特に、信頼できないソースからのJavaScriptコードを実行することは、セキュリティリスクを伴う可能性があります。**
### 過去に話題になった、またはブックマークレットとして応用できるアイデア
1. **ページ上の全要素を回転させる (CSS3を利用)**
* **アイデア:** ページ内の全てのHTML要素を取得し、それぞれに回転するCSSスタイルを適用します。
* **コード例 (ブックマークレット向け):**
```javascript
javascript:(function(){document.body.style.transition='transform 2s'; document.body.style.transform='rotate(360deg)'; setTimeout(function(){document.body.style.transition=''; document.body.style.transform='';}, 2000);})();
```
または、各要素を個別に回転させるようなより複雑なものも考えられます。
```javascript
javascript:(function(){[].forEach.call(document.querySelectorAll('*'),function(a){a.style.transition='transform 1s';a.style.transform='rotate('+(Math.random()*720-360)+'deg)';});setTimeout(function(){[].forEach.call(document.querySelectorAll('*'),function(a){a.style.transition='';a.style.transform='';});},5000)})();
```
* **URL欄での動作:** 最近のブラウザでは直接入力での実行は難しいでしょう。ブックマークレットとして保存・実行すれば動作する可能性があります。
2. **ページ上の画像を全て同じ画像に置き換える**
* **アイデア:** ページ内の全ての `<img>` タグを取得し、その `src` 属性を指定した画像のURLに書き換えます。
* **コード例 (ブックマークレット向け):**
```javascript
javascript:(function(){var newImageURL='ここに置き換えたい画像のURL'; [].forEach.call(document.getElementsByTagName('img'),function(img){img.src=newImageURL;});})();
```
* **URL欄での動作:** 同様に、直接入力は難しいですが、ブックマークレットなら可能です。
3. **ページ上の文字をランダムな文字や記号に書き換える(いわゆる「文字化け」風)**
* **アイデア:** ページ内のテキストノードを探索し、その内容をランダムな文字列に置き換えます。これは元に戻すのが難しく、実用性は低いですが、視覚的な「崩壊」効果はあります。
* **コード例 (非常に破壊的なので注意・ブックマークレット向け):**
```javascript
javascript:(function(){var all=document.getElementsByTagName("*");for(var i=0,max=all.length;i<max;i++){if(all[i].childNodes.length>0){for(var j=0,max_j=all[i].childNodes.length;j<max_j;j++){if(all[i].childNodes[j].nodeType==3){all[i].childNodes[j].nodeValue=all[i].childNodes[j].nodeValue.replace(/[^\s]/g,function(){return String.fromCharCode(Math.floor(Math.random()*65536));});}}}}}();
```
* **URL欄での動作:** 直接入力は難しいでしょう。**この種のスクリプトはページの表示を完全に破壊する可能性があるため、使用には最大限の注意が必要です。**
4. **ページ全体を編集可能にする**
* **アイデア:** `document.body.contentEditable` プロパティを `true` に設定します。
* **コード:**
```javascript
javascript:document.body.contentEditable='true'; void 0;
```
* **URL欄での動作:** これは比較的シンプルなため、ブラウザや設定によってはまだURL欄から直接実行できる可能性があります(ただし、`javascript:` が削除されないように手入力する必要があるかもしれません)。しかし、これもセキュリティポリシーによりブロックされることが増えています。ブックマークレットとしては依然として有効な場合が多いです。
5. **画面を点滅させる、色を反転させる**
* **アイデア:** CSSを使って `filter: invert(1)` や、背景色と文字色を短時間で切り替えることで実現します。
* **コード例 (色反転ブックマークレット):**
```javascript
javascript:(function(){var s=document.body.style; if(s.filter=='invert(1)'){s.filter=''}else{s.filter='invert(1)'}})();
```
* **URL欄での動作:** 直接入力は難しいでしょう。ブックマークレットなら可能です。
### なぜURL欄からのJavaScript実行は制限されるのか
主な理由はセキュリティです。
* **XSS (クロスサイトスクリプティング) 対策:** 悪意のあるウェブサイトや第三者が、ユーザーに特定のJavaScriptコードをURL欄に貼り付けて実行させることで、セッション情報を盗んだり、予期せぬ操作を行わせたりする攻撃を防ぐためです。
* **ユーザー保護:** 知識のないユーザーが、意図せず危険なコードを実行してしまうことを防ぐためです。
### ブックマークレットとしての利用
上記のようなコードの多くは、ブックマークレットとしてブラウザのブックマークに登録することで、クリックひとつで実行できるようになります。ブックマークレットを作成するには、通常、ブックマークのURL欄に `javascript:` で始まるコードを記述します。
**ブックマークレットの例 (ページタイトルをアラート表示):**
`javascript:alert(document.title);`
### まとめ
URL欄に直接JavaScriptを打ち込んでページに派手な視覚効果を与えるというのは、現代のブラウザ環境ではセキュリティ上の制約から非常に難しくなっています。もしそのような効果を試したい場合は、
* **ブラウザの開発者コンソール (F12キーなどで開けます) を使う:** コンソールからは任意のJavaScriptを実行できます。
* **ブックマークレットとして登録する:** 安全性を確認した上で、自己責任でブックマークレットとして利用する。
という方法が現実的です。
繰り返しになりますが、インターネット上で見つけた見慣れないJavaScriptコードを安易に実行することは避けてください。コードの内容を理解し、安全性を確認した上で、自己責任において試すようにしましょう。
URL欄からのJavaScript実行
├
掲示板に新しい機能を追加するというのは、とても面白い試みですね。提示された例は、入力されたHTMLをそのまま別ウィンドウで実行するというもので、アイデア次第で様々な応用ができそうです。
以下に、独創的または参考となりそうな機能のアイデアをいくつか提案します。多くはクライアントサイドのJavaScriptで実現できる可能性があります。
### 1. テキスト分析・可視化系の機能
* **簡易マークダウンプレビュー機能:**
* 掲示板にMarkdown記法(例: `# 見出し`, `*太字*`, `[リンク](URL)`)で書かれたテキストを、リアルタイムまたはボタンクリックでHTMLに変換してプレビュー表示します。
* **実現方法:** JavaScriptでMarkdownをHTMLに変換するライブラリ(例: Marked.js, Showdown.js)を利用します。変換後のHTMLを別ウィンドウや指定の要素内に表示します。
```javascript
// Marked.jsを使う場合のイメージ
function previewMarkdown(textareaId, previewAreaId) {
const markdownText = document.getElementById(textareaId).value;
const html = marked.parse(markdownText); // marked.parse() はMarked.jsの関数
const previewWindow = window.open();
previewWindow.document.open();
previewWindow.document.write(html);
previewWindow.document.close();
// もしくは特定のdivに表示
// document.getElementById(previewAreaId).innerHTML = html;
}
```
```html
<TEXTAREA id="markdownInput"># テスト見出し\n*太字*\n[Google](https://google.com)</TEXTAREA>
<INPUT type="button" value="Markdownプレビュー" onClick="previewMarkdown('markdownInput', 'previewArea');">
<DIV id="previewArea"></DIV>
```
* **テキストのQRコード生成機能:**
* 掲示板に書かれたテキスト(URL、メールアドレス、自由な文章など)をQRコードとして表示します。スマートフォンで簡単に読み取れるようになります。
* **実現方法:** JavaScriptのQRコード生成ライブラリ(例: qrcode.js, Ringo_QRジェネレーター)を利用します。生成されたQRコードを画像として表示します。
```javascript
// qrcode.js を使う場合のイメージ (別途ライブラリの読み込みが必要)
function generateQR(textareaId, qrcodeDivId) {
const text = document.getElementById(textareaId).value;
const qrcodeDiv = document.getElementById(qrcodeDivId);
qrcodeDiv.innerHTML = ""; // 既存のQRコードをクリア
new QRCode(qrcodeDiv, {
text: text,
width: 128,
height: 128
});
}
```
```html
<TEXTAREA id="qrText">ここにQRコードにしたいテキストを入力</TEXTAREA>
<INPUT type="button" value="QRコード生成" onClick="generateQR('qrText', 'qrcodeDisplay');">
<DIV id="qrcodeDisplay"></DIV>
```
* **テキスト読み上げ機能:**
* 掲示板に書かれたテキストを音声で読み上げます。アクセシビリティ向上にも繋がります。
* **実現方法:** Web Speech API の `SpeechSynthesisUtterance` を利用します。
```javascript
function speakText(textareaId) {
if ('speechSynthesis' in window) {
const text = document.getElementById(textareaId).value;
const utterance = new SpeechSynthesisUtterance(text);
// オプションで言語や声を設定可能
// utterance.lang = 'ja-JP';
window.speechSynthesis.speak(utterance);
} else {
alert('ごめんなさい、お使いのブラウザは音声読み上げに対応していません。');
}
}
```
```html
<TEXTAREA id="speechText">読み上げたいテキストを入力してください。</TEXTAREA>
<INPUT type="button" value="読み上げる" onClick="speakText('speechText');">
```
### 2. インタラクティブ・エンタメ系の機能
* **簡易計算機能:**
* 掲示板に書かれた簡単な数式(例: `(100+50)*2`)を計算して結果を表示します。
* **実現方法:** JavaScriptの `eval()` 関数を利用できますが、セキュリティリスクがあるため注意が必要です。より安全な数式パーサーライブラリ(例: math.js)の利用を推奨します。
```javascript
// eval() を使う場合の簡易的な例 (セキュリティリスクに注意!)
function calculate(textareaId) {
try {
const expression = document.getElementById(textareaId).value;
const result = eval(expression);
alert('計算結果: ' + result);
} catch (e) {
alert('計算式が正しくないか、計算できませんでした。');
}
}
```
```html
<TEXTAREA id="calcText">2 * (3 + 4)</TEXTAREA>
<INPUT type="button" value="計算する" onClick="calculate('calcText');">
```
* **アスキーアート(AA)整形表示機能:**
* 掲示板に投稿されたアスキーアートが綺麗に表示されるように、フォントを指定したり、`<pre>` タグで囲んで表示したりします。
* **実現方法:** 表示する際に、CSSでAAに適したフォント(例: `MS PGothic`, `monospace`)を指定し、`<pre>` タグで整形済みテキストとして扱います。
```javascript
function showAA(textareaId) {
const aaText = document.getElementById(textareaId).value;
const aaWindow = window.open();
aaWindow.document.open();
aaWindow.document.write('<pre style="font-family: \'MS PGothic\', \'IPAMonaPGothic\', monospace; line-height: 1.2em;">' + escapeHtml(aaText) + '</pre>');
aaWindow.document.close();
}
// HTMLエスケープ関数 (XSS対策)
function escapeHtml(str) {
const div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}
```
```html
<TEXTAREA id="aaText">
,.へ
___ ム i
「 ヒ_i〉 ゝ 〈
ト ノ iニ(()
i { | ヽ
i i i }
| i | 「
| i | |
</TEXTAREA>
<INPUT type="button" value="AAを整形して表示" onClick="showAA('aaText');">
```
* **縦書き表示機能:**
* 掲示板のテキストを縦書きで表示します。小説や詩などを扱う掲示板で喜ばれるかもしれません。
* **実現方法:** CSSの `writing-mode: vertical-rl;` を利用します。
```javascript
function showVertical(textareaId) {
const text = document.getElementById(textareaId).value;
const verticalWindow = window.open();
verticalWindow.document.open();
verticalWindow.document.write('<div style="writing-mode: vertical-rl; height: 90vh; font-family: \'MS Mincho\', \'Hiragino Mincho ProN\', serif;">' + escapeHtml(text) + '</div>');
verticalWindow.document.close();
}
```
```html
<TEXTAREA id="verticalText" style="width:300px; height:100px;">ここに縦書きにしたい文章を入力します。
日本語の表示に適しています。</TEXTAREA>
<INPUT type="button" value="縦書きで表示" onClick="showVertical('verticalText');">
```
### 3. 外部連携・ユーティリティ系の機能
* **選択テキストで検索エンジン検索:**
* テキストエリア内で選択した文字列を、GoogleやTwitterなどの検索エンジンで検索するボタンを追加します。
* **実現方法:** `window.getSelection().toString()` で選択範囲のテキストを取得し、検索エンジンのURLに組み込んで新しいタブで開きます。
```javascript
function searchSelectedText(textareaId, engine) {
const textarea = document.getElementById(textareaId);
const selectedText = textarea.value.substring(textarea.selectionStart, textarea.selectionEnd);
if (selectedText) {
let searchUrl;
if (engine === 'google') {
searchUrl = 'https://www.google.com/search?q=' + encodeURIComponent(selectedText);
} else if (engine === 'twitter') {
searchUrl = 'https://twitter.com/search?q=' + encodeURIComponent(selectedText);
}
if (searchUrl) {
window.open(searchUrl, '_blank');
}
} else {
alert('検索したいテキストを選択してください。');
}
}
```
```html
<TEXTAREA id="searchTextarea">検索したいテキストをここに入力し、一部を選択してください。</TEXTAREA>
<INPUT type="button" value="選択範囲をGoogle検索" onClick="searchSelectedText('searchTextarea', 'google');">
<INPUT type="button" value="選択範囲をTwitter検索" onClick="searchSelectedText('searchTextarea', 'twitter');">
```
* **地図連携機能:**
* 掲示板に地名や住所が書かれていた場合、それをGoogle Mapsなどの地図サービスで表示するボタンを追加します。
* **実現方法:** テキストエリアの文字列(または選択された部分)を地図サービスのURLパラメータとして渡します。
```javascript
function openMap(textareaId) {
const address = document.getElementById(textareaId).value;
if (address) {
const mapUrl = 'https://www.google.com/maps?q=' + encodeURIComponent(address);
window.open(mapUrl, '_blank');
} else {
alert('地名や住所を入力してください。');
}
}
```
```html
<TEXTAREA id="addressText">東京スカイツリー</TEXTAREA>
<INPUT type="button" value="地図で表示" onClick="openMap('addressText');">
```
### 注意点
* **セキュリティ:** ユーザーが入力した内容をHTMLとして実行したり、`eval()` を使用したりする際には、クロスサイトスクリプティング(XSS)などのセキュリティリスクに十分注意してください。必要に応じて、入力値のサニタイズ(無害化処理)や、より安全な代替手段の利用を検討しましょう。提示された `jikkou` 関数の例は、入力された内容をそのまま `document.write` しているため、悪意のあるスクリプトを埋め込まれると実行されてしまう可能性があります。`escapeHtml` のような関数でエスケープ処理を挟むなどの対策が考えられます。
* **ユーザビリティ:** 機能を追加する際は、ユーザーが直感的に使えるようなインターフェースを心がけることが大切です。ボタンの配置や説明文なども工夫してみてください。
* **掲示板のテーマとの整合性:** 掲示板のテーマや利用者に合った機能を選ぶと、より活用されやすくなります。例えば、プログラミング系の掲示板であればコードハイライトや実行環境連携、創作系の掲示板であれば縦書き表示やルビ振り機能などが考えられます。
これらのアイデアが、あなたの掲示板開発の参考になれば幸いです。独創的な機能で、より魅力的な掲示板を作成してください。
掲示板に新しい機能を追加する
├
非公開
これらSMEMOの変更予定
├
<html xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv=Content-Type content="text/html; charset=shift_jis">
<meta name=ProgId content=Excel.Sheet>
<meta name=Generator content="Microsoft Excel 15">
<link id=Main-File rel=Main-File href="../Book1.htm">
<link rel=File-List href=filelist.xml>
<![if IE]>
<base href="file:///C:/CE594991/Book1.files/sheet001.htm"
id="webarch_temp_base_tag">
<![endif]>
<link rel=Stylesheet href=stylesheet.css>
<style>
<!--table
{mso-displayed-decimal-separator:"\.";
mso-displayed-thousand-separator:"\,";}
@page
{margin:.75in .7in .75in .7in;
mso-header-margin:.3in;
mso-footer-margin:.3in;}
ruby
{ruby-align:left;}
rt
{color:windowtext;
font-size:6.0pt;
font-weight:400;
font-style:normal;
text-decoration:none;
font-family:游ゴシック, monospace;
mso-font-charset:128;
mso-char-type:katakana;
display:none;}
-->
</style>
<![if !supportTabStrip]><script language="JavaScript">
<!--
function fnUpdateTabs()
{
if (parent.window.g_iIEVer>=4) {
if (parent.document.readyState=="complete"
&& parent.frames['frTabs'].document.readyState=="complete")
parent.fnSetActiveSheet(0);
else
window.setTimeout("fnUpdateTabs();",150);
}
}
if (window.name!="frSheet")
window.location.replace("../Book1.htm");
else
fnUpdateTabs();
//-->
</script>
<![endif]>
</head>
<body link="#0563C1" vlink="#954F72">
<div _ngcontent-ng-c2986768429="" dir=ltr style='--animation-duration: 600ms;
--fade-animation-function: linear;animation: 0s ease 0s 1 normal none running none;
appearance: none;background:padding-box border-box rgba(0, 0, 0, 0);inset: auto;
columns: auto;contain: none;container: none;content: normal;cx: 0px;cy: 0px;
d: none;fill: rgb(0, 0, 0);flex: 0 1 auto;font-size-adjust: none;font-kerning: auto;
font-optical-sizing: auto;font-feature-settings: normal;font-variation-settings: normal;
font-stretch: normal;gap: normal;hyphens: manual;interactivity: auto;
isolation: auto;marker: none;mask: none;offset: normal;opacity: 1;order: 0;
orphans: 2;outline: rgb(27, 28, 29) none 0px;overlay: none;perspective: none;
quotes: auto;r: 0px;resize: none;rotate: none;rx: auto;ry: auto;scale: none;
speak: normal;stroke: none;transform: none;transition: all;translate: none;
widows: 2;x: 0px;y: 0px;zoom: 1'>
<table border=0 cellpadding=0 cellspacing=0 width=2376 style='border-collapse:
collapse;table-layout:fixed;width:1782pt'>
<col width=72 span=33 style='width:54pt'>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl65 colspan=22 dir=LTR width=1584 style='height:18.75pt;
mso-ignore:colspan;width:1188pt'>Meta Quest
3の標準ブラウザで楽しめる3Dサイトですね!WebXR技術を使ったサイトや、3Dモデルをインタラクティブに表示するサイトなど、様々な体験が可能です。いくつかおすすめのサイトをご紹介します。</td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl66 colspan=4 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>1. Sketchfab (スケッチファブ)</td>
<td colspan=29 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=29 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>内容:<font class="font5">
膨大な数の3Dモデルが公開されているプラットフォームです。ユーザーが作成したキャラクター、建物、乗り物、アート作品など、多種多様なモデルをブラウザ上で3Dで鑑賞できます。多くのモデルはVRモードにも対応しており、Meta
Quest 3で臨場感あふれる体験が可能です。</font></td>
<td colspan=4 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=19 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>楽しみ方:<font class="font5">
興味のあるカテゴリーを検索したり、人気のあるモデルを眺めたりするだけでも楽しめます。気に入ったモデルを拡大・縮小・回転させながら細部まで観察できます。</font></td>
<td colspan=14 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl68 colspan=4 dir=LTR style='height:18.75pt;mso-ignore:
colspan'><a href="https://sketchfab.com/" target="_blank" rel=noopener
externallink="" _nghost-ng-c3138787759=""
jslog="197247;track:generic_click,impression;BardVeMetadataKey:[["r_60412c52abd1a943","c_bdc636b0cf977e2f",null,"rc_9257646b5e9128ca",null,null,"ja",null,null,null,null,1,0]]"
style='animation: 0s ease 0s 1 normal none running none;appearance: none;
background:padding-box border-box rgba(0, 0, 0, 0);inset: auto;columns: auto;
contain: none;container: none;content: normal;cursor:pointer;cx: 0px;
cy: 0px;d: none;fill: rgb(0, 0, 0);flex: 0 1 auto;font-size-adjust: none;
font-kerning: auto;font-optical-sizing: auto;font-feature-settings: normal;
font-variation-settings: normal;font-stretch: normal;gap: normal;hyphens: manual;
interactivity: auto;isolation: auto;marker: none;mask: none;offset: normal;
opacity: 1;order: 0;orphans: 2;outline: rgb(11, 87, 208) none 0px;overlay: none;
perspective: none;quotes: auto;r: 0px;resize: none;rotate: none;rx: auto;
ry: auto;scale: none;speak: normal;stroke: none;transform: none;transition: all;
translate: none;widows: 2;x: 0px;y: 0px;zoom: 1'>URL:<font class="font8">
https://sketchfab.com/</font></a></td>
<td colspan=29 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl66 colspan=4 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>2. Mozilla Hubs (モジラハブズ)</td>
<td colspan=29 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=31 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>内容:<font class="font5">
Mozillaが開発した、ブラウザベースのソーシャルVRプラットフォームです。アバターを使って仮想空間に入り、他のユーザーとコミュニケーションを取ったり、3Dオブジェクトを共有したりできます。特別なソフトウェアのインストールは不要で、Meta
Quest 3のブラウザから直接アクセスできます。</font></td>
<td colspan=2 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=17 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>楽しみ方:<font class="font5">
公開されているルームに参加したり、自分でルームを作成して友人を招待したりできます。会議やイベント、気軽な雑談など、様々な用途で活用できます。</font></td>
<td colspan=16 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl68 colspan=4 dir=LTR style='height:18.75pt;mso-ignore:
colspan'><a href="https://hubs.mozilla.com/" target="_blank" rel=noopener
externallink="" _nghost-ng-c3138787759=""
jslog="197247;track:generic_click,impression;BardVeMetadataKey:[["r_60412c52abd1a943","c_bdc636b0cf977e2f",null,"rc_9257646b5e9128ca",null,null,"ja",null,null,null,null,1,0]]"
style='animation: 0s ease 0s 1 normal none running none;appearance: none;
background:padding-box border-box rgba(0, 0, 0, 0);inset: auto;columns: auto;
contain: none;container: none;content: normal;cursor:pointer;cx: 0px;
cy: 0px;d: none;fill: rgb(0, 0, 0);flex: 0 1 auto;font-size-adjust: none;
font-kerning: auto;font-optical-sizing: auto;font-feature-settings: normal;
font-variation-settings: normal;font-stretch: normal;gap: normal;hyphens: manual;
interactivity: auto;isolation: auto;marker: none;mask: none;offset: normal;
opacity: 1;order: 0;orphans: 2;outline: rgb(11, 87, 208) none 0px;overlay: none;
perspective: none;quotes: auto;r: 0px;resize: none;rotate: none;rx: auto;
ry: auto;scale: none;speak: normal;stroke: none;transform: none;transition: all;
translate: none;widows: 2;x: 0px;y: 0px;zoom: 1'>URL:<font class="font8">
https://hubs.mozilla.com/</font></a></td>
<td colspan=29 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl66 colspan=8 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>3. WebXR Experiments (ウェブエックスアール エクスペリメンツ)</td>
<td colspan=25 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=23 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>内容:<font class="font5">
Googleが提供する、WebXR技術を使った様々な実験的なデモを体験できるサイトです。シンプルなゲームや、インタラクティブなアート、教育的なコンテンツなど、WebXRの可能性を感じられるものが多くあります。</font></td>
<td colspan=10 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=19 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>楽しみ方:<font class="font5">
色々なデモを試してみて、WebXRでどのようなことができるのかを体験してみてください。Meta Quest
3のコントローラーを使った操作に対応しているものもあります。</font></td>
<td colspan=14 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl68 colspan=12 dir=LTR style='height:18.75pt;mso-ignore:
colspan'><a href="https://experiments.withgoogle.com/collection/webxr"
target="_blank" rel=noopener externallink="" _nghost-ng-c3138787759=""
jslog="197247;track:generic_click,impression;BardVeMetadataKey:[["r_60412c52abd1a943","c_bdc636b0cf977e2f",null,"rc_9257646b5e9128ca",null,null,"ja",null,null,null,null,1,0]]"
style='animation: 0s ease 0s 1 normal none running none;appearance: none;
background:padding-box border-box rgba(0, 0, 0, 0);inset: auto;columns: auto;
contain: none;container: none;content: normal;cursor:pointer;cx: 0px;
cy: 0px;d: none;fill: rgb(0, 0, 0);flex: 0 1 auto;font-size-adjust: none;
font-kerning: auto;font-optical-sizing: auto;font-feature-settings: normal;
font-variation-settings: normal;font-stretch: normal;gap: normal;hyphens: manual;
interactivity: auto;isolation: auto;marker: none;mask: none;offset: normal;
opacity: 1;order: 0;orphans: 2;outline: rgb(11, 87, 208) none 0px;overlay: none;
perspective: none;quotes: auto;r: 0px;resize: none;rotate: none;rx: auto;
ry: auto;scale: none;speak: normal;stroke: none;transform: none;transition: all;
translate: none;widows: 2;x: 0px;y: 0px;zoom: 1'>URL:<font class="font8">
https://experiments.withgoogle.com/collection/webxr
(具体的なデモは時期によって入れ替わる可能性があります)</font></a></td>
<td colspan=21 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl66 colspan=3 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>4. A-Frame (エーフレーム)</td>
<td colspan=30 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=24 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>内容:<font class="font5">
WebXRコンテンツを簡単に作成できるオープンソースのウェブフレームワークです。A-Frameの公式サイトには、A-Frameを使って作られた様々なデモや事例が紹介されており、その多くをMeta
Quest 3のブラウザで体験できます。</font></td>
<td colspan=9 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=23 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>楽しみ方:<font class="font5">
公式サイトの「Examples」や「Showcase」のセクションをチェックして、気に入ったデモを試してみてください。プログラミングの知識が少しあれば、自分で簡単なWebXRコンテンツを作ることも可能です。</font></td>
<td colspan=10 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl68 colspan=3 dir=LTR style='height:18.75pt;mso-ignore:
colspan'><a href="https://aframe.io/" target="_blank" rel=noopener
externallink="" _nghost-ng-c3138787759=""
jslog="197247;track:generic_click,impression;BardVeMetadataKey:[["r_60412c52abd1a943","c_bdc636b0cf977e2f",null,"rc_9257646b5e9128ca",null,null,"ja",null,null,null,null,1,0]]"
style='animation: 0s ease 0s 1 normal none running none;appearance: none;
background:padding-box border-box rgba(0, 0, 0, 0);inset: auto;columns: auto;
contain: none;container: none;content: normal;cursor:pointer;cx: 0px;
cy: 0px;d: none;fill: rgb(0, 0, 0);flex: 0 1 auto;font-size-adjust: none;
font-kerning: auto;font-optical-sizing: auto;font-feature-settings: normal;
font-variation-settings: normal;font-stretch: normal;gap: normal;hyphens: manual;
interactivity: auto;isolation: auto;marker: none;mask: none;offset: normal;
opacity: 1;order: 0;orphans: 2;outline: rgb(11, 87, 208) none 0px;overlay: none;
perspective: none;quotes: auto;r: 0px;resize: none;rotate: none;rx: auto;
ry: auto;scale: none;speak: normal;stroke: none;transform: none;transition: all;
translate: none;widows: 2;x: 0px;y: 0px;zoom: 1'>URL:<font class="font8">
https://aframe.io/</font></a></td>
<td colspan=30 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl66 colspan=4 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>5. Matterport (マーターポート)</td>
<td colspan=29 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=26 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>内容:<font class="font5">
現実の空間を3Dスキャンして、没入型のデジタルツインを作成するプラットフォームです。不動産の内見、美術館のバーチャルツアー、店舗の紹介などに活用されています。Meta
Quest 3のブラウザでこれらの3D空間をウォークスルー体験できます。</font></td>
<td colspan=7 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=15 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>楽しみ方:<font class="font5">
公開されている様々な物件や施設をバーチャルで訪れてみましょう。まるでその場にいるかのような感覚で空間を探索できます。</font></td>
<td colspan=18 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl68 colspan=4 dir=LTR style='height:18.75pt;mso-ignore:
colspan'><a href="https://matterport.com/discover" target="_blank"
rel=noopener externallink="" _nghost-ng-c3138787759=""
jslog="197247;track:generic_click,impression;BardVeMetadataKey:[["r_60412c52abd1a943","c_bdc636b0cf977e2f",null,"rc_9257646b5e9128ca",null,null,"ja",null,null,null,null,1,0]]"
style='animation: 0s ease 0s 1 normal none running none;appearance: none;
background:padding-box border-box rgba(0, 0, 0, 0);inset: auto;columns: auto;
contain: none;container: none;content: normal;cursor:pointer;cx: 0px;
cy: 0px;d: none;fill: rgb(0, 0, 0);flex: 0 1 auto;font-size-adjust: none;
font-kerning: auto;font-optical-sizing: auto;font-feature-settings: normal;
font-variation-settings: normal;font-stretch: normal;gap: normal;hyphens: manual;
interactivity: auto;isolation: auto;marker: none;mask: none;offset: normal;
opacity: 1;order: 0;orphans: 2;outline: rgb(11, 87, 208) none 0px;overlay: none;
perspective: none;quotes: auto;r: 0px;resize: none;rotate: none;rx: auto;
ry: auto;scale: none;speak: normal;stroke: none;transform: none;transition: all;
translate: none;widows: 2;x: 0px;y: 0px;zoom: 1'>URL:<font class="font8">
https://matterport.com/discover</font></a></td>
<td colspan=29 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl66 colspan=2 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>その他・注意点</td>
<td colspan=31 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=22 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>ウェブサイト側の対応:<font class="font5"> すべての3DコンテンツがMeta Quest
3のブラウザで完璧に動作するとは限りません。サイトによっては、VRモードへの切り替えボタン(ゴーグルのアイコンなど)がある場合があります。</font></td>
<td colspan=11 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=19 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>ブラウザの更新:<font class="font5"> Meta Quest
3のブラウザは定期的にアップデートされます。最新バージョンにすることで、より多くのWebXRコンテンツが快適に楽しめるようになる可能性があります。</font></td>
<td colspan=14 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=10 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>インターネット接続:<font class="font5"> 快適な体験のためには、安定したインターネット接続が必要です。</font></td>
<td colspan=23 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl65 colspan=24 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>これらのサイトを参考に、Meta Quest 3の標準ブラウザで3Dの世界をお楽しみください!
新しいサイトも続々と登場しているので、ぜひご自身でも「WebXR」などのキーワードで検索して、お気に入りのサイトを見つけてみてください。</div>
</td>
<td colspan=9 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 colspan=33 style='height:18.75pt;mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl65 colspan=14 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>
<div _ngcontent-ng-c2986768429="" dir=ltr style='--animation-duration: 600ms;
--fade-animation-function: linear;animation: 0s ease 0s 1 normal none running none;
appearance: none;background:padding-box border-box rgba(0, 0, 0, 0);
inset: auto;columns: auto;contain: none;container: none;content: normal;
cx: 0px;cy: 0px;d: none;fill: rgb(0, 0, 0);flex: 0 1 auto;font-size-adjust: none;
font-kerning: auto;font-optical-sizing: auto;font-feature-settings: normal;
font-variation-settings: normal;font-stretch: normal;gap: normal;hyphens: manual;
interactivity: auto;isolation: auto;marker: none;mask: none;offset: normal;
opacity: 1;order: 0;orphans: 2;outline: rgb(27, 28, 29) none 0px;overlay: none;
perspective: none;quotes: auto;r: 0px;resize: none;rotate: none;rx: auto;
ry: auto;scale: none;speak: normal;stroke: none;transform: none;transition: all;
translate: none;widows: 2;x: 0px;y: 0px;zoom: 1'>かしこまりました。Meta Quest
3の標準ブラウザで楽しめる3Dサイトについて、さらにリサーチを行い、より多くの情報をお届けします。</td>
<td colspan=19 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl65 colspan=11 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>前回ご紹介したサイトに加えて、さらにいくつかのカテゴリーや具体的なサイトを探してみました。</td>
<td colspan=22 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl66 colspan=5 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>1. ゲーム・インタラクティブコンテンツ</td>
<td colspan=28 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=4 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>PlayCanvas (プレイキャンバス)</td>
<td colspan=29 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl69 colspan=24 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>内容:<font class="font5">
WebGLを利用した3Dゲームやインタラクティブなコンテンツを開発・公開できるプラットフォームです。多くのデモやユーザー作成ゲームが公開されており、Meta
Quest 3のブラウザで直接プレイできるものもあります。</font></td>
<td colspan=9 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl69 colspan=23 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>楽しみ方:<font class="font5">
「Explore」セクションや「Learn」セクションから様々なプロジェクトを探し、気に入ったものを試してみてください。高品質なグラフィックのゲームや、物理演算を使った面白いデモなどが見つかります。</font></td>
<td colspan=10 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl70 colspan=4 dir=LTR style='height:18.75pt;mso-ignore:
colspan'><a href="https://playcanvas.com/explore" target="_blank"
rel=noopener externallink="" _nghost-ng-c3138787759=""
jslog="197247;track:generic_click,impression;BardVeMetadataKey:[["r_161723bf14105b48","c_bdc636b0cf977e2f",null,"rc_6884f423b0b82aa3",null,null,"ja",null,null,null,null,1,0]]"
style='animation: 0s ease 0s 1 normal none running none;appearance: none;
background:padding-box border-box rgba(0, 0, 0, 0);inset: auto;columns: auto;
contain: none;container: none;content: normal;cursor:pointer;cx: 0px;
cy: 0px;d: none;fill: rgb(0, 0, 0);flex: 0 1 auto;font-size-adjust: none;
font-kerning: auto;font-optical-sizing: auto;font-feature-settings: normal;
font-variation-settings: normal;font-stretch: normal;gap: normal;hyphens: manual;
interactivity: auto;isolation: auto;marker: none;mask: none;offset: normal;
opacity: 1;order: 0;orphans: 2;outline: rgb(11, 87, 208) none 0px;overlay: none;
perspective: none;quotes: auto;r: 0px;resize: none;rotate: none;rx: auto;
ry: auto;scale: none;speak: normal;stroke: none;transform: none;transition: all;
translate: none;widows: 2;x: 0px;y: 0px;zoom: 1'>URL:<font class="font8">
https://playcanvas.com/explore</font></a></td>
<td colspan=29 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=5 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>Construct 3 (コンストラクト3) - Arcade</td>
<td colspan=28 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl69 colspan=26 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>内容:<font class="font5"> プログラミング知識がなくてもゲームを制作できるツール「Construct
3」の公式サイトには、ユーザーが作成したゲームを公開・プレイできる「Arcade」というセクションがあります。WebXRに対応したゲームもいくつか見つけることができます。</font></td>
<td colspan=7 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl69 colspan=17 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>楽しみ方:<font class="font5">
「Arcade」で「VR」や「WebXR」といったキーワードで検索してみると、Meta Quest
3で楽しめるカジュアルなゲームが見つかるかもしれません。</font></td>
<td colspan=16 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl70 colspan=9 dir=LTR style='height:18.75pt;mso-ignore:
colspan'><a
href="https://www.google.com/search?q=https://www.construct.net/en/arcade"
target="_blank" rel=noopener externallink="" _nghost-ng-c3138787759=""
jslog="197247;track:generic_click,impression;BardVeMetadataKey:[["r_161723bf14105b48","c_bdc636b0cf977e2f",null,"rc_6884f423b0b82aa3",null,null,"ja",null,null,null,null,1,0]]"
style='animation: 0s ease 0s 1 normal none running none;appearance: none;
background:padding-box border-box rgba(0, 0, 0, 0);inset: auto;columns: auto;
contain: none;container: none;content: normal;cursor:pointer;cx: 0px;
cy: 0px;d: none;fill: rgb(0, 0, 0);flex: 0 1 auto;font-size-adjust: none;
font-kerning: auto;font-optical-sizing: auto;font-feature-settings: normal;
font-variation-settings: normal;font-stretch: normal;gap: normal;hyphens: manual;
interactivity: auto;isolation: auto;marker: none;mask: none;offset: normal;
opacity: 1;order: 0;orphans: 2;outline: rgb(11, 87, 208) none 0px;overlay: none;
perspective: none;quotes: auto;r: 0px;resize: none;rotate: none;rx: auto;
ry: auto;scale: none;speak: normal;stroke: none;transform: none;transition: all;
translate: none;widows: 2;x: 0px;y: 0px;zoom: 1'>URL:<font class="font8">
https://www.google.com/search?q=https://www.construct.net/en/arcade</font></a></td>
<td colspan=24 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=9 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>CrazyGames (クレイジーゲームズ) や Poki (ポキ) などのブラウザゲームサイト</td>
<td colspan=24 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl69 colspan=29 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>内容:<font class="font5">
これらのサイトには、多数の無料ブラウザゲームが集まっています。数は少ないかもしれませんが、「VR」や「3D」といったカテゴリーで検索すると、Meta
Quest 3のブラウザでプレイ可能なシンプルな3Dゲームや、擬似的なVR体験ができるゲームが見つかることがあります。</font></td>
<td colspan=4 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl69 colspan=17 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>楽しみ方:<font class="font5"> 気軽に遊べるゲームを探している場合に試してみてください。すべてのゲームがMeta
Quest 3に最適化されているわけではない点にご注意ください。</font></td>
<td colspan=16 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl70 colspan=6 dir=LTR style='height:18.75pt;mso-ignore:
colspan'><a href="https://www.crazygames.com/" target="_blank" rel=noopener
externallink="" _nghost-ng-c3138787759=""
jslog="197247;track:generic_click,impression;BardVeMetadataKey:[["r_161723bf14105b48","c_bdc636b0cf977e2f",null,"rc_6884f423b0b82aa3",null,null,"ja",null,null,null,null,1,0]]"
style='animation: 0s ease 0s 1 normal none running none;appearance: none;
background:padding-box border-box rgba(0, 0, 0, 0);inset: auto;columns: auto;
contain: none;container: none;content: normal;cursor:pointer;cx: 0px;
cy: 0px;d: none;fill: rgb(0, 0, 0);flex: 0 1 auto;font-size-adjust: none;
font-kerning: auto;font-optical-sizing: auto;font-feature-settings: normal;
font-variation-settings: normal;font-stretch: normal;gap: normal;hyphens: manual;
interactivity: auto;isolation: auto;marker: none;mask: none;offset: normal;
opacity: 1;order: 0;orphans: 2;outline: rgb(11, 87, 208) none 0px;overlay: none;
perspective: none;quotes: auto;r: 0px;resize: none;rotate: none;rx: auto;
ry: auto;scale: none;speak: normal;stroke: none;transform: none;transition: all;
translate: none;widows: 2;x: 0px;y: 0px;zoom: 1'>CrazyGames URL:<font
class="font8"> https://www.crazygames.com/</font></a></td>
<td colspan=27 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl70 colspan=5 dir=LTR style='height:18.75pt;mso-ignore:
colspan'><a href="https://poki.jp/" target="_blank" rel=noopener
externallink="" _nghost-ng-c3138787759=""
jslog="197247;track:generic_click,impression;BardVeMetadataKey:[["r_161723bf14105b48","c_bdc636b0cf977e2f",null,"rc_6884f423b0b82aa3",null,null,"ja",null,null,null,null,1,0]]"
style='animation: 0s ease 0s 1 normal none running none;appearance: none;
background:padding-box border-box rgba(0, 0, 0, 0);inset: auto;columns: auto;
contain: none;container: none;content: normal;cursor:pointer;cx: 0px;
cy: 0px;d: none;fill: rgb(0, 0, 0);flex: 0 1 auto;font-size-adjust: none;
font-kerning: auto;font-optical-sizing: auto;font-feature-settings: normal;
font-variation-settings: normal;font-stretch: normal;gap: normal;hyphens: manual;
interactivity: auto;isolation: auto;marker: none;mask: none;offset: normal;
opacity: 1;order: 0;orphans: 2;outline: rgb(11, 87, 208) none 0px;overlay: none;
perspective: none;quotes: auto;r: 0px;resize: none;rotate: none;rx: auto;
ry: auto;scale: none;speak: normal;stroke: none;transform: none;transition: all;
translate: none;widows: 2;x: 0px;y: 0px;zoom: 1'>Poki URL:<font class="font8">
https://poki.jp/ (日本語対応)</font></a></td>
<td colspan=28 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl66 colspan=3 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>2. 教育・学習・アート</td>
<td colspan=30 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=7 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>Google Arts & Culture (グーグル アーツアンドカルチャー)</td>
<td colspan=26 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl69 colspan=26 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>内容:<font class="font5">
世界中の美術館や博物館のコレクションをオンラインで鑑賞できるプラットフォームです。一部の展示や作品は3Dで表示されたり、ストリートビューのように館内を巡ったりすることが可能です。WebXRに対応したコンテンツも増えつつあります。</font></td>
<td colspan=7 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl69 colspan=19 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>楽しみ方:<font class="font5">
有名な絵画を高解像度で細部まで鑑賞したり、歴史的な遺物を3Dで様々な角度から眺めたりできます。バーチャルツアーで世界中の文化遺産を訪れるのもおすすめです。</font></td>
<td colspan=14 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl70 colspan=5 dir=LTR style='height:18.75pt;mso-ignore:
colspan'><a href="https://artsandculture.google.com/" target="_blank"
rel=noopener externallink="" _nghost-ng-c3138787759=""
jslog="197247;track:generic_click,impression;BardVeMetadataKey:[["r_161723bf14105b48","c_bdc636b0cf977e2f",null,"rc_6884f423b0b82aa3",null,null,"ja",null,null,null,null,1,0]]"
style='animation: 0s ease 0s 1 normal none running none;appearance: none;
background:padding-box border-box rgba(0, 0, 0, 0);inset: auto;columns: auto;
contain: none;container: none;content: normal;cursor:pointer;cx: 0px;
cy: 0px;d: none;fill: rgb(0, 0, 0);flex: 0 1 auto;font-size-adjust: none;
font-kerning: auto;font-optical-sizing: auto;font-feature-settings: normal;
font-variation-settings: normal;font-stretch: normal;gap: normal;hyphens: manual;
interactivity: auto;isolation: auto;marker: none;mask: none;offset: normal;
opacity: 1;order: 0;orphans: 2;outline: rgb(11, 87, 208) none 0px;overlay: none;
perspective: none;quotes: auto;r: 0px;resize: none;rotate: none;rx: auto;
ry: auto;scale: none;speak: normal;stroke: none;transform: none;transition: all;
translate: none;widows: 2;x: 0px;y: 0px;zoom: 1'>URL:<font class="font8">
https://artsandculture.google.com/</font></a></td>
<td colspan=28 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=7 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>The Extended Mind (ザ・エクステンデッド・マインド)</td>
<td colspan=26 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl69 colspan=19 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>内容:<font class="font5">
様々なWebXRアート作品や実験的なプロジェクトをキュレーションしているサイトです。ブラウザでアクセスできるユニークで示唆に富んだVR/AR体験が見つかります。</font></td>
<td colspan=14 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl69 colspan=18 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>楽しみ方:<font class="font5">
アーティスティックな表現や、新しいテクノロジーの可能性に触れたい方におすすめです。各作品のコンセプトを理解しながら体験すると、より深く楽しめます。</font></td>
<td colspan=15 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl70 colspan=8 dir=LTR style='height:18.75pt;mso-ignore:
colspan'><a
href="https://www.google.com/search?q=https://theextendedmind.com/"
target="_blank" rel=noopener externallink="" _nghost-ng-c3138787759=""
jslog="197247;track:generic_click,impression;BardVeMetadataKey:[["r_161723bf14105b48","c_bdc636b0cf977e2f",null,"rc_6884f423b0b82aa3",null,null,"ja",null,null,null,null,1,0]]"
style='animation: 0s ease 0s 1 normal none running none;appearance: none;
background:padding-box border-box rgba(0, 0, 0, 0);inset: auto;columns: auto;
contain: none;container: none;content: normal;cursor:pointer;cx: 0px;
cy: 0px;d: none;fill: rgb(0, 0, 0);flex: 0 1 auto;font-size-adjust: none;
font-kerning: auto;font-optical-sizing: auto;font-feature-settings: normal;
font-variation-settings: normal;font-stretch: normal;gap: normal;hyphens: manual;
interactivity: auto;isolation: auto;marker: none;mask: none;offset: normal;
opacity: 1;order: 0;orphans: 2;outline: rgb(11, 87, 208) none 0px;overlay: none;
perspective: none;quotes: auto;r: 0px;resize: none;rotate: none;rx: auto;
ry: auto;scale: none;speak: normal;stroke: none;transform: none;transition: all;
translate: none;widows: 2;x: 0px;y: 0px;zoom: 1'>URL:<font class="font8">
https://www.google.com/search?q=https://theextendedmind.com/</font></a></td>
<td colspan=25 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=3 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>Within (ウィズイン)</td>
<td colspan=30 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl69 colspan=25 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>内容:<font class="font5">
高品質なVRドキュメンタリーやストーリーテリングコンテンツを制作・配信しているプラットフォームです。一部の作品はWebXR経由でブラウザから視聴できる場合があります。(専用アプリでの視聴がメインの場合もあります)</font></td>
<td colspan=8 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl69 colspan=11 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>楽しみ方:<font class="font5"> 感動的な物語や、社会的なメッセージ性の強い作品など、没入感の高い映像体験ができます。</font></td>
<td colspan=22 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl70 colspan=3 dir=LTR style='height:18.75pt;mso-ignore:
colspan'><a href="https://www.with.in/" target="_blank" rel=noopener
externallink="" _nghost-ng-c3138787759=""
jslog="197247;track:generic_click,impression;BardVeMetadataKey:[["r_161723bf14105b48","c_bdc636b0cf977e2f",null,"rc_6884f423b0b82aa3",null,null,"ja",null,null,null,null,1,0]]"
style='animation: 0s ease 0s 1 normal none running none;appearance: none;
background:padding-box border-box rgba(0, 0, 0, 0);inset: auto;columns: auto;
contain: none;container: none;content: normal;cursor:pointer;cx: 0px;
cy: 0px;d: none;fill: rgb(0, 0, 0);flex: 0 1 auto;font-size-adjust: none;
font-kerning: auto;font-optical-sizing: auto;font-feature-settings: normal;
font-variation-settings: normal;font-stretch: normal;gap: normal;hyphens: manual;
interactivity: auto;isolation: auto;marker: none;mask: none;offset: normal;
opacity: 1;order: 0;orphans: 2;outline: rgb(11, 87, 208) none 0px;overlay: none;
perspective: none;quotes: auto;r: 0px;resize: none;rotate: none;rx: auto;
ry: auto;scale: none;speak: normal;stroke: none;transform: none;transition: all;
translate: none;widows: 2;x: 0px;y: 0px;zoom: 1'>URL:<font class="font8">
https://www.with.in/</font></a></td>
<td colspan=30 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl66 colspan=6 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>3. 3Dモデルビューア・プラットフォーム (再掲・補足)</td>
<td colspan=27 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=4 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>Sketchfab (スケッチファブ)</td>
<td colspan=29 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl69 colspan=33 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>補足:<font class="font5">
前回もご紹介しましたが、教育的なコンテンツ(例:人体の解剖モデル、歴史的建造物の再現モデル)や、製品の3Dモデルなども豊富にあります。検索機能を活用して、興味のある分野のモデルを探してみてください。Meta
Quest 3のブラウザで「VR」モードを選択すると、より没入感のある鑑賞が可能です。</font></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl66 colspan=4 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>4. その他のWebXR関連リソース</td>
<td colspan=29 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=5 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>WebXR Samples (WebXR サンプル)</td>
<td colspan=28 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl69 colspan=20 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>内容:<font class="font5"> WebXR
APIの様々な機能を使った基本的なサンプルコードとデモが公開されています。開発者向けではありますが、どのようなことができるのかを具体的に知りたい場合に参考になります。</font></td>
<td colspan=13 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl69 colspan=18 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>楽しみ方:<font class="font5"> 各デモをMeta Quest
3のブラウザで試すことで、WebXRの基本的なインタラクション(コントローラーの入力、オブジェクトの選択など)を体験できます。</font></td>
<td colspan=15 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl70 colspan=6 dir=LTR style='height:18.75pt;mso-ignore:
colspan'><a href="https://immersive-web.github.io/webxr-samples/"
target="_blank" rel=noopener externallink="" _nghost-ng-c3138787759=""
jslog="197247;track:generic_click,impression;BardVeMetadataKey:[["r_161723bf14105b48","c_bdc636b0cf977e2f",null,"rc_6884f423b0b82aa3",null,null,"ja",null,null,null,null,1,0]]"
style='animation: 0s ease 0s 1 normal none running none;appearance: none;
background:padding-box border-box rgba(0, 0, 0, 0);inset: auto;columns: auto;
contain: none;container: none;content: normal;cursor:pointer;cx: 0px;
cy: 0px;d: none;fill: rgb(0, 0, 0);flex: 0 1 auto;font-size-adjust: none;
font-kerning: auto;font-optical-sizing: auto;font-feature-settings: normal;
font-variation-settings: normal;font-stretch: normal;gap: normal;hyphens: manual;
interactivity: auto;isolation: auto;marker: none;mask: none;offset: normal;
opacity: 1;order: 0;orphans: 2;outline: rgb(11, 87, 208) none 0px;overlay: none;
perspective: none;quotes: auto;r: 0px;resize: none;rotate: none;rx: auto;
ry: auto;scale: none;speak: normal;stroke: none;transform: none;transition: all;
translate: none;widows: 2;x: 0px;y: 0px;zoom: 1'>URL:<font class="font8">
https://immersive-web.github.io/webxr-samples/</font></a></td>
<td colspan=27 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=2 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>Hello WebXR!</td>
<td colspan=31 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl69 colspan=12 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>内容:<font class="font5">
WebXRコンテンツのポータルサイトの一つで、様々なデモやゲーム、体験へのリンクが集められています。</font></td>
<td colspan=21 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl69 colspan=7 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>楽しみ方:<font class="font5"> 新しいWebXRコンテンツを発見するのに役立ちます。</font></td>
<td colspan=26 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl70 colspan=8 dir=LTR style='height:18.75pt;mso-ignore:
colspan'><a href="https://www.google.com/search?q=https://www.hellowebxr.com/"
target="_blank" rel=noopener externallink="" _nghost-ng-c3138787759=""
jslog="197247;track:generic_click,impression;BardVeMetadataKey:[["r_161723bf14105b48","c_bdc636b0cf977e2f",null,"rc_6884f423b0b82aa3",null,null,"ja",null,null,null,null,1,0]]"
style='animation: 0s ease 0s 1 normal none running none;appearance: none;
background:padding-box border-box rgba(0, 0, 0, 0);inset: auto;columns: auto;
contain: none;container: none;content: normal;cursor:pointer;cx: 0px;
cy: 0px;d: none;fill: rgb(0, 0, 0);flex: 0 1 auto;font-size-adjust: none;
font-kerning: auto;font-optical-sizing: auto;font-feature-settings: normal;
font-variation-settings: normal;font-stretch: normal;gap: normal;hyphens: manual;
interactivity: auto;isolation: auto;marker: none;mask: none;offset: normal;
opacity: 1;order: 0;orphans: 2;outline: rgb(11, 87, 208) none 0px;overlay: none;
perspective: none;quotes: auto;r: 0px;resize: none;rotate: none;rx: auto;
ry: auto;scale: none;speak: normal;stroke: none;transform: none;transition: all;
translate: none;widows: 2;x: 0px;y: 0px;zoom: 1'>URL:<font class="font8">
https://www.google.com/search?q=https://www.hellowebxr.com/</font></a></td>
<td colspan=25 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl66 colspan=7 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>Meta Quest 3のブラウザで3Dサイトを快適に楽しむためのヒント</td>
<td colspan=26 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=11 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>ブックマークの活用:<font class="font5"> 気に入ったサイトや、頻繁に訪れるサイトはブックマークしておくと便利です。</font></td>
<td colspan=22 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=23 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>ウィンドウモードとVRモードの切り替え:<font class="font5"> サイトによっては、VRゴーグルのアイコンや「Enter
VR」といったボタンが表示されます。これをクリックすることで、より没入感のあるVRモードに切り替えることができます。</font></td>
<td colspan=10 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=19 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>コントローラー操作の確認:<font class="font5">
サイトによってコントローラーの操作方法が異なる場合があります。多くの場合、ポインターで選択し、トリガーボタンで決定する操作が基本となります。</font></td>
<td colspan=14 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=16 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>キャッシュのクリア:<font class="font5">
まれにサイトの表示がおかしくなることがあります。その場合は、ブラウザのキャッシュをクリアすると改善されることがあります。</font></td>
<td colspan=17 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl67 colspan=11 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>Wi-Fi環境の確認:<font class="font5">
途切れのないスムーズな体験のためには、高速で安定したWi-Fi環境が推奨されます。</font></td>
<td colspan=22 style='mso-ignore:colspan'></td>
</tr>
<tr height=25 style='height:18.75pt'>
<td height=25 class=xl65 colspan=21 dir=LTR style='height:18.75pt;mso-ignore:
colspan'>これらの情報が、Meta Quest
3での3Dサイト体験をさらに豊かなものにするお役に立てれば幸いです。WebXRの世界は日々進化していますので、新しいサイトやコンテンツも積極的に探してみてください。</div>
</td>
<td colspan=12 style='mso-ignore:colspan'></td>
</tr>
<![if supportMisalignedColumns]>
<tr height=0 style='display:none'>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
<td width=72 style='width:54pt'></td>
</tr>
<![endif]>
</table>
</body>
</html>
Meta Quest 3の標準ブラウザで楽しめる3Dサイトーー
├
geminiの回答を、・・・からコピーを選んでExcelに貼り付け、単一のHTMを選んでbook1.hmt で保存 ブラウザで開いてソースコードを持ってきたのが上のやつ
これやれば リンクは一応切れない。
Meta Quest 3の標準ブラウザで楽しめる3Dサイトですね!WebXR技術を使ったサイトや、3Dモデルをインタラクティブに表示するサイトなど、様々な体験が可能です。いくつかおすすめのサイトをご紹介します。
1. Sketchfab (スケッチファブ)
内容: 膨大な数の3Dモデルが公開されているプラットフォームです。ユーザーが作成したキャラクター、建物、乗り物、アート作品など、多種多様なモデルをブラウザ上で3Dで鑑賞できます。多くのモデルはVRモードにも対応しており、Meta Quest 3で臨場感あふれる体験が可能です。
楽しみ方: 興味のあるカテゴリーを検索したり、人気のあるモデルを眺めたりするだけでも楽しめます。気に入ったモデルを拡大・縮小・回転させながら細部まで観察できます。
URL: https://sketchfab.com/
2. Mozilla Hubs (モジラハブズ)
内容: Mozillaが開発した、ブラウザベースのソーシャルVRプラットフォームです。アバターを使って仮想空間に入り、他のユーザーとコミュニケーションを取ったり、3Dオブジェクトを共有したりできます。特別なソフトウェアのインストールは不要で、Meta Quest 3のブラウザから直接アクセスできます。
楽しみ方: 公開されているルームに参加したり、自分でルームを作成して友人を招待したりできます。会議やイベント、気軽な雑談など、様々な用途で活用できます。
URL: https://hubs.mozilla.com/
3. WebXR Experiments (ウェブエックスアール エクスペリメンツ)
内容: Googleが提供する、WebXR技術を使った様々な実験的なデモを体験できるサイトです。シンプルなゲームや、インタラクティブなアート、教育的なコンテンツなど、WebXRの可能性を感じられるものが多くあります。
楽しみ方: 色々なデモを試してみて、WebXRでどのようなことができるのかを体験してみてください。Meta Quest 3のコントローラーを使った操作に対応しているものもあります。
URL: https://experiments.withgoogle.com/collection/webxr (具体的なデモは時期によって入れ替わる可能性があります)
4. A-Frame (エーフレーム)
内容: WebXRコンテンツを簡単に作成できるオープンソースのウェブフレームワークです。A-Frameの公式サイトには、A-Frameを使って作られた様々なデモや事例が紹介されており、その多くをMeta Quest 3のブラウザで体験できます。
楽しみ方: 公式サイトの「Examples」や「Showcase」のセクションをチェックして、気に入ったデモを試してみてください。プログラミングの知識が少しあれば、自分で簡単なWebXRコンテンツを作ることも可能です。
URL: https://aframe.io/
5. Matterport (マーターポート)
内容: 現実の空間を3Dスキャンして、没入型のデジタルツインを作成するプラットフォームです。不動産の内見、美術館のバーチャルツアー、店舗の紹介などに活用されています。Meta Quest 3のブラウザでこれらの3D空間をウォークスルー体験できます。
楽しみ方: 公開されている様々な物件や施設をバーチャルで訪れてみましょう。まるでその場にいるかのような感覚で空間を探索できます。
URL: https://matterport.com/discover
その他・注意点
ウェブサイト側の対応: すべての3DコンテンツがMeta Quest 3のブラウザで完璧に動作するとは限りません。サイトによっては、VRモードへの切り替えボタン(ゴーグルのアイコンなど)がある場合があります。
ブラウザの更新: Meta Quest 3のブラウザは定期的にアップデートされます。最新バージョンにすることで、より多くのWebXRコンテンツが快適に楽しめるようになる可能性があります。
インターネット接続: 快適な体験のためには、安定したインターネット接続が必要です。
これらのサイトを参考に、Meta Quest 3の標準ブラウザで3Dの世界をお楽しみください! 新しいサイトも続々と登場しているので、ぜひご自身でも「WebXR」などのキーワードで検索して、お気に入りのサイトを見つけてみてください。
かしこまりました。Meta Quest 3の標準ブラウザで楽しめる3Dサイトについて、さらにリサーチを行い、より多くの情報をお届けします。
前回ご紹介したサイトに加えて、さらにいくつかのカテゴリーや具体的なサイトを探してみました。
1. ゲーム・インタラクティブコンテンツ
PlayCanvas (プレイキャンバス)
内容: WebGLを利用した3Dゲームやインタラクティブなコンテンツを開発・公開できるプラットフォームです。多くのデモやユーザー作成ゲームが公開されており、Meta Quest 3のブラウザで直接プレイできるものもあります。
楽しみ方: 「Explore」セクションや「Learn」セクションから様々なプロジェクトを探し、気に入ったものを試してみてください。高品質なグラフィックのゲームや、物理演算を使った面白いデモなどが見つかります。
URL: https://playcanvas.com/explore
Construct 3 (コンストラクト3) - Arcade
内容: プログラミング知識がなくてもゲームを制作できるツール「Construct 3」の公式サイトには、ユーザーが作成したゲームを公開・プレイできる「Arcade」というセクションがあります。WebXRに対応したゲームもいくつか見つけることができます。
楽しみ方: 「Arcade」で「VR」や「WebXR」といったキーワードで検索してみると、Meta Quest 3で楽しめるカジュアルなゲームが見つかるかもしれません。
URL: https://www.google.com/search?q=https://www.construct.net/en/arcade
CrazyGames (クレイジーゲームズ) や Poki (ポキ) などのブラウザゲームサイト
内容: これらのサイトには、多数の無料ブラウザゲームが集まっています。数は少ないかもしれませんが、「VR」や「3D」といったカテゴリーで検索すると、Meta Quest 3のブラウザでプレイ可能なシンプルな3Dゲームや、擬似的なVR体験ができるゲームが見つかることがあります。
楽しみ方: 気軽に遊べるゲームを探している場合に試してみてください。すべてのゲームがMeta Quest 3に最適化されているわけではない点にご注意ください。
CrazyGames URL: https://www.crazygames.com/
Poki URL: https://poki.jp/ (日本語対応)
2. 教育・学習・アート
Google Arts & Culture (グーグル アーツアンドカルチャー)
内容: 世界中の美術館や博物館のコレクションをオンラインで鑑賞できるプラットフォームです。一部の展示や作品は3Dで表示されたり、ストリートビューのように館内を巡ったりすることが可能です。WebXRに対応したコンテンツも増えつつあります。
楽しみ方: 有名な絵画を高解像度で細部まで鑑賞したり、歴史的な遺物を3Dで様々な角度から眺めたりできます。バーチャルツアーで世界中の文化遺産を訪れるのもおすすめです。
URL: https://artsandculture.google.com/
The Extended Mind (ザ・エクステンデッド・マインド)
内容: 様々なWebXRアート作品や実験的なプロジェクトをキュレーションしているサイトです。ブラウザでアクセスできるユニークで示唆に富んだVR/AR体験が見つかります。
楽しみ方: アーティスティックな表現や、新しいテクノロジーの可能性に触れたい方におすすめです。各作品のコンセプトを理解しながら体験すると、より深く楽しめます。
URL: https://www.google.com/search?q=https://theextendedmind.com/
Within (ウィズイン)
内容: 高品質なVRドキュメンタリーやストーリーテリングコンテンツを制作・配信しているプラットフォームです。一部の作品はWebXR経由でブラウザから視聴できる場合があります。(専用アプリでの視聴がメインの場合もあります)
楽しみ方: 感動的な物語や、社会的なメッセージ性の強い作品など、没入感の高い映像体験ができます。
URL: https://www.with.in/
3. 3Dモデルビューア・プラットフォーム (再掲・補足)
Sketchfab (スケッチファブ)
補足: 前回もご紹介しましたが、教育的なコンテンツ(例:人体の解剖モデル、歴史的建造物の再現モデル)や、製品の3Dモデルなども豊富にあります。検索機能を活用して、興味のある分野のモデルを探してみてください。Meta Quest 3のブラウザで「VR」モードを選択すると、より没入感のある鑑賞が可能です。
4. その他のWebXR関連リソース
WebXR Samples (WebXR サンプル)
内容: WebXR APIの様々な機能を使った基本的なサンプルコードとデモが公開されています。開発者向けではありますが、どのようなことができるのかを具体的に知りたい場合に参考になります。
楽しみ方: 各デモをMeta Quest 3のブラウザで試すことで、WebXRの基本的なインタラクション(コントローラーの入力、オブジェクトの選択など)を体験できます。
URL: https://immersive-web.github.io/webxr-samples/
Hello WebXR!
内容: WebXRコンテンツのポータルサイトの一つで、様々なデモやゲーム、体験へのリンクが集められています。
楽しみ方: 新しいWebXRコンテンツを発見するのに役立ちます。
URL: https://www.google.com/search?q=https://www.hellowebxr.com/
Meta Quest 3のブラウザで3Dサイトを快適に楽しむためのヒント
ブックマークの活用: 気に入ったサイトや、頻繁に訪れるサイトはブックマークしておくと便利です。
ウィンドウモードとVRモードの切り替え: サイトによっては、VRゴーグルのアイコンや「Enter VR」といったボタンが表示されます。これをクリックすることで、より没入感のあるVRモードに切り替えることができます。
コントローラー操作の確認: サイトによってコントローラーの操作方法が異なる場合があります。多くの場合、ポインターで選択し、トリガーボタンで決定する操作が基本となります。
キャッシュのクリア: まれにサイトの表示がおかしくなることがあります。その場合は、ブラウザのキャッシュをクリアすると改善されることがあります。
Wi-Fi環境の確認: 途切れのないスムーズな体験のためには、高速で安定したWi-Fi環境が推奨されます。
これらの情報が、Meta Quest 3での3Dサイト体験をさらに豊かなものにするお役に立てれば幸いです。WebXRの世界は日々進化していますので、新しいサイトやコンテンツも積極的に探してみてください。
Meta Quest 3の標準ブラウザで楽しめる3Dサイト
├
複数のファイルが有り、先頭が一定の種類でまとまっている。例えば、momo-123.jpg momo-assd.jpg dda-qqqwqw.jpg dda-ttttrerer.jpgなど。これらを、まずフォルダ分けして移動する。momoフォルダ ddaフォルダなど。 次に圧縮して、1つずつの圧縮ファイルにしたい momo.zip dda.zip のように。このようなバッチを作成できないか
できます!Windows環境で使える「バッチファイル(.bat)」を作成すれば、以下のような処理が可能です:
---
### ✅ やりたいこと(まとめ)
1. 複数のファイル(例:`momo-123.jpg`, `dda-abc.jpg`)がある。
2. 接頭辞(例:`momo`, `dda`)ごとにフォルダを作り、ファイルを移動。
3. 各フォルダを個別に ZIP 圧縮(例:`momo.zip`, `dda.zip`)。
---
### 🛠 バッチファイルのコード(`sort_and_zip.bat`)
```bat
@echo off
setlocal enabledelayedexpansion
REM 作業ディレクトリ(スクリプトのある場所に設定)
cd /d "%~dp0"
REM 拡張子を指定(jpg以外も対応可能)
set EXT=jpg
REM ファイルをループ処理
for %%f in (*.%EXT%) do (
REM 接頭辞をファイル名の先頭からハイフンまで抽出(例:momo)
for /f "tokens=1 delims=-" %%a in ("%%~nxf") do (
set PREFIX=%%a
REM フォルダがなければ作成
if not exist "!PREFIX!" (
mkdir "!PREFIX!"
)
REM 該当フォルダにファイル移動
move "%%f" "!PREFIX!\"
)
)
REM フォルダをZIP圧縮(PowerShell使用)
for /d %%d in (*) do (
REM 拡張子を除いたZIPファイル名を作成
powershell -command "Compress-Archive -Path '%%d\*' -DestinationPath '%%d.zip'"
)
echo 完了しました!
pause
```
---
### 🔧 使い方
1. 上記コードをメモ帳などにコピペ。
2. `sort_and_zip.bat` として保存。
3. 対象の画像ファイル(例:`momo-1.jpg`など)があるフォルダにこの `.bat` を配置。
4. ダブルクリックで実行。
---
### 📝 注意点
- Windows 標準の `Compress-Archive` は PowerShell で使えるので、特別なソフト不要。
- 拡張子が `.jpg` 以外(例:`.png`, `.txt`など)の場合は、`set EXT=jpg` を変更。
---
もしファイル名のルールがもう少し複雑だったり、他のOS(Mac / Linux)用スクリプトも必要なら、その辺りも対応できるよ!
圧縮-chatgpt
├
複数のファイルが有り、先頭が一定の種類でまとまっている。例えば、momo-123.jpg momo-assd.jpg dda-qqqwqw.jpg dda-ttttrerer.jpgなど。これらを、まずフォルダ分けして移動する。momoフォルダ ddaフォルダなど。 次に圧縮して、1つずつの圧縮ファイルにしたい momo.zip dda.zip のように。このようなバッチを作成できないか
はい、承知いたしました。指定された形式のファイル名(例: `momo-123.jpg`, `dda-qqqwqw.jpg`)に基づいて、ファイルをプレフィックスごと(`momo`, `dda`)にフォルダ分けし、その後、各フォルダを個別のZIPファイル(`momo.zip`, `dda.zip`)に圧縮するバッチファイルを作成します。
このバッチファイルは、Windows 10 (バージョン1803以降) または Windows 11 に標準搭載されている `tar` コマンドを使用してZIPファイルを作成します。外部ツールのインストールは不要です。
```batch
@echo off
setlocal enabledelayedexpansion
REM --- 設定項目 ---
REM 処理したいファイルがあるフォルダのパスを指定してください
REM バッチファイルと同じフォルダにある場合は "." のままでOK
set "TARGET_DIR=."
REM --- 設定項目ここまで ---
REM 作業ディレクトリに移動 (エラーチェック付き)
pushd "%TARGET_DIR%"
if errorlevel 1 (
echo ERROR: 指定されたフォルダが見つかりません: %TARGET_DIR%
pause
exit /b 1
)
echo ファイルのフォルダ分けを開始します...
echo 対象フォルダ: %CD%
echo ---
REM フォルダ分け処理
for %%F in (*-*) do (
REM ファイル名にハイフンが含まれるファイルのみ処理
echo Processing file: "%%F"
REM ハイフンより前の部分(プレフィックス)を取得
for /f "tokens=1 delims=-" %%P in ("%%~nF") do (
set "Prefix=%%P"
REM プレフィックス名のフォルダが存在しない場合は作成
if not exist "!Prefix!" (
echo Creating folder: "!Prefix!"
mkdir "!Prefix!"
if errorlevel 1 (
echo ERROR: Folder creation failed for "!Prefix!". Skipping file "%%F".
goto :skip_move
)
)
REM ファイルをプレフィックス名のフォルダに移動
echo Moving "%%F" to "!Prefix!\"
move "%%F" "!Prefix!\" > nul
if errorlevel 1 (
echo WARN: Failed to move "%%F". It might already exist in "!Prefix!" or be in use.
)
)
:skip_move
)
echo ---
echo フォルダ分けが完了しました。
echo ---
echo 各フォルダのZIP圧縮を開始します...
echo ---
REM 圧縮処理 (カレントディレクトリにあるフォルダを対象)
for /d %%D in (*) do (
REM "." や ".." ではなく、実際に作成または存在するフォルダのみ対象
if not "%%~nxD"=="." if not "%%~nxD"==".." (
set "FolderName=%%~nxD"
set "ZipFileName=!FolderName!.zip"
REM 同名のZIPファイルが既に存在するか確認(上書きしない場合)
REM if exist "!ZipFileName!" (
REM echo Skipping: "!ZipFileName!" already exists.
REM ) else (
echo Compressing folder "!FolderName!" to "!ZipFileName!"...
REM tarコマンドでフォルダをZIP圧縮 (-a: 自動圧縮形式選択, -c: 作成, -f: ファイル名指定)
tar -a -c -f "!ZipFileName!" "!FolderName!" > nul 2> nul
if errorlevel 1 (
echo ERROR: Failed to compress "!FolderName!". Check if tar command is available or if the folder is empty/inaccessible.
) else (
echo Success: "!ZipFileName!" created.
)
REM )
REM 上記の if exist ... else (...) のコメントアウトを外すと、既存のZIPファイルを上書きしません。
REM 現在は既存ファイルがあっても上書きします。
)
)
echo ---
echo 全ての処理が完了しました。
REM 元のディレクトリに戻る
popd
endlocal
pause
```
**バッチファイルの使い方**
1. 上記のコードをテキストエディタ(メモ帳など)にコピー&ペーストします。
2. **`REM --- 設定項目 ---`** の部分を編集します。
* `TARGET_DIR`: 処理したいファイル(`momo-123.jpg` など)が保存されているフォルダのパスを指定します。このバッチファイルと同じフォルダにファイルがある場合は、 `.` のままで大丈夫です。
3. ファイルを保存します。ファイル名は自由ですが、拡張子は `.bat` または `.cmd` にします。(例: `organize_and_zip.bat`)
4. **注意:** このバッチファイルを実行すると、`TARGET_DIR` 内のファイルがサブフォルダに移動され、その後フォルダがZIP圧縮されます。**元に戻す機能はないため、事前にファイルのバックアップを取るか、コピーしたファイルで試すことを強く推奨します。**
5. 作成したバッチファイルをダブルクリックして実行します。
**処理の流れ**
1. 指定された `TARGET_DIR` に移動します。
2. フォルダ内のファイルのうち、名前にハイフン (`-`) が含まれるものを一つずつチェックします。
3. ファイル名からハイフンより前の部分(プレフィックス)を抽出します。
4. そのプレフィックスと同じ名前のフォルダが存在しなければ作成します。
5. ファイルをそのフォルダに移動します。
6. 全てのファイルの移動が終わったら、`TARGET_DIR` 内にある全てのフォルダ(ファイル移動によって作成されたフォルダ)を一つずつチェックします。
7. 各フォルダを、フォルダ名と同じ名前のZIPファイル(例: `momo` フォルダなら `momo.zip`)に圧縮します。標準の `tar` コマンドを使用します。
8. 全ての処理が終わったらメッセージを表示して終了します。
**補足事項**
* **`tar` コマンド:** Windows 10 (バージョン1803以降) / Windows 11 に標準搭載されています。もし古いWindows OSを使用している場合は、別途 7-Zip などのコマンドライン圧縮ツールをインストールし、バッチファイル内の `tar` コマンド部分をそのツールのコマンドに書き換える必要があります。
* **エラー処理:** 簡単なエラーチェック(フォルダ作成失敗、ファイル移動失敗、圧縮失敗)を含めていますが、完璧ではありません。
* **既存ファイルの扱い:** ファイル移動時に移動先に同名ファイルがあると、`move` コマンドはデフォルトでは上書きしません(エラーになる場合があります)。ZIP圧縮は、既存のZIPファイルがあれば `tar` コマンドは通常上書きします。
* **ファイル名の制限:** フォルダ名として使用できない文字(`\ / : * ? " < > |` など)がプレフィックスに含まれている場合、フォルダ作成に失敗する可能性があります。
* **空フォルダ:** ファイル移動の結果、空になったフォルダもZIP圧縮の対象になります(中身が空のZIPファイルが作成されます)。
圧縮ーgemini
├
【蒸留モデル】DeepSeek-R1ローカル実行時におすすめのモデル #macOS - Qiita
https://qiita.com/yonaka15/items/a69790be6eacd726f770
Ollamaを活用したDeepSeek-R1のローカルLLM構築ガイド - GPT Master
https://chatgpt-enterprise.jp/blog/ollama-deepseek-r1/
無料で学ぶ!生成AIとバズった技術まとめ(LLM、LangChain、Dify、SAM2、Stable Diffusion、RVCなど) #langchain - Qiita
https://qiita.com/birdwatcher/items/b5cc66ce59095dee5625
DeepSeek R1をほぼ準備なしからローカルGPUで動かす|しぴちゃん
https://note.com/cppp_cpchan/n/n3c1039c80dd0
妻にDeepSeek R1をローカルPCで動かす方法を教えたのでここに手順を残します|胡椒 - こしょう
https://note.com/torauma9/n/n1b2447ab4398
でえぷしいく
├
old
│├
ccdからcue+binに変換する方法
CCD(CloneCD Control File)とBIN(Binary Image)の組み合わせは、CDやDVDのイメージファイル形式としてよく使われていました。
これをCUEシート(.cue)とBINファイル(.bin)の組み合わせに変換する方法はいくつかあります。
理由:
CUE/BIN形式の汎用性: CUE/BIN形式は、多くのメディアプレイヤーやエミュレーターで広くサポートされています。
CUEシートの重要性: CUEシートには、トラック情報やインデックス情報などが記述されており、CDの構造を正確に再現するために重要です。
変換方法:
主に以下のツールや方法が考えられます。
1. IsoBuster (Windows - 有料、無料版あり):
IsoBusterは、CD/DVD/BDイメージファイルを扱う強力なツールです。無料版でも多くの機能が利用できます。
手順:
IsoBusterを起動します。
「ファイル」メニューから「イメージファイルを開く」を選択し、CCDファイル(またはBINファイル)を開きます。
左側のツリービューで、イメージファイルを選択します。
右クリックして「CDイメージを抽出」または同様のオプションを選択します。
出力形式として「.CUE (.BIN)」を選択し、保存先を指定して「OK」をクリックします。
IsoBusterがCCDファイルとBINファイルからCUEシートを生成し、指定した場所に保存します。
2. CDMage (Windows - フリーソフト):
CDMageは、CDイメージファイルを編集したり、形式を変換したりできるフリーソフトです。
手順:
CDMageを起動します。
「ファイル」メニューから「イメージを開く」を選択し、CCDファイルを開きます。
「ファイル」メニューから「保存」を選択します。
「ファイルの種類」で「CDRDAO/BIN (*.CUE)」を選択し、保存先とファイル名を指定して「保存」をクリックします。
CDMageがCUEシートとBINファイルを生成します。
3. bchunk (コマンドラインツール - Linux/macOS/Windows):
bchunkは、BIN/CUE形式とCCD/IMG/SUB形式を相互に変換できるコマンドラインツールです。
インストール (例: Debian/Ubuntu):
Bash
sudo apt-get install bchunk
使い方:
Bash
bchunk <イメージファイル.ccd> <出力ファイル名.bin>
例えば、image.ccd を output.bin と output.cue に変換する場合は以下のようになります。
Bash
bchunk image.ccd output.bin
bchunkは、CCDファイルからトラック情報を読み取り、対応するBINファイルを作成し、CUEシート(output.cue)を生成します。
4. その他ツール:
他にも、Imgburn (Windows - フリーソフト) など、様々なCD/DVDイメージファイル操作ツールが同様の変換機能を持っている可能性があります。
これらのツールのドキュメントやオプションを確認してみてください。
注意点:
CCDファイルと対応するBINファイルが同じ場所に存在している必要があります。
変換ツールによっては、CCDファイルだけでなく、BINファイルも指定する必要がある場合があります。
変換後のCUEシートの内容が正しいか、テキストエディタなどで確認することをおすすめします。
特にトラックの開始位置やファイル名などが正確に記述されているか確認してください。
これらの方法を試して、CCD+BIN形式のイメージファイルをCUE+BIN形式に変換してみてください。
通常は、IsoBusterやCDMageのようなGUIツールが比較的簡単に操作できるためおすすめです。
コマンドラインに慣れている場合は、bchunkも効率的な選択肢となります。
ccd2bincue
│├
非公開
VR調べた情報など
│├
★決算処分★シングルトランジスタFMマイク - aitendo
1石FMマイクキット - aitendo
3石FMマイクキット - aitendo
クリスマス・ツリーきっと - aitendo
テスラコイルドライブモジュール - aitendo
回転LEDダイスキット - aitendo
楽しい32曲和音メロディキット - aitendo
作りやすい4桁デジタル時計 - aitendo
https://tech-blog.abeja.asia/entry/advent-2023-day24
L298Nデュアルモータードライバ
特徴 ・2Aまで流せる(最大25W) ・極性反転が可能 ・PWM制御が可能 ・2回路ある ・5V出力あるのでマイコン動かせる
Arduinoの信号で大電流の操作が可能。アンプとして使える。
O O
U U モーターA
T T
4 3
┌────┴┴──┐
│ ・・│ENB(ジャンパするとONOFF、外すとPWM)
│ ・│IN4 モーターA用
│ ・│IN3 モーターA用
│ ・│IN2 モーター@用
│ ・│IN1 モーター@用
│ ・・│ENA(ジャンパするとONOFF、外すとPWM)
│ 5VOUT├ 5V出力
│ ・・ GND├ GND(後ろのジャンパをすると5V出力する、外すと5V出力しない)
│ 12VIN├ 12V入力
└────┬┬──┘
O O
U U
T T モーター@
1 2
https://www.aitendo.com/product/3288
https://www.aitendo.com/product/13862
https://www.aitendo.com/product/20564
調べた情報など
│├
http://p-bookmark.sakura.ne.jp/
http://p-bookmark.sakura.ne.jp/index00.htm
http://p-bookmark.sakura.ne.jp/hakoran/
http://p-bookmark.sakura.ne.jp/sure/index.cgi
http://hatebune.web.fc2.com/
http://p-bookmark.sakura.ne.jp/r-search/index.cgi?pon=
aaaaaa
│├
#include <Arduino.h>
void setup() {
Serial.begin(9600);
while (!Serial) {
; // シリアルポートが利用可能になるまで待機
}
}
void loop() {
if (Serial.available()) {
int num1 = Serial.parseInt(); // 最初の数値を読み取る
char op = Serial.read(); // 演算子を読み取る
int num2 = Serial.parseInt(); // 2番目の数値を読み取る
int result = 0; // 計算結果を格納する変数
// 演算子に基づいて計算を行う
switch (op) {
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '*':
result = num1 * num2;
break;
case '/':
result = num1 / num2;
break;
default:
Serial.println("無効な演算子");
break;
}
// 計算結果をシリアルモニタに出力
Serial.print("結果: ");
Serial.println(result);
}
}
このプログラムでは、シリアル通信を使用してユーザーから数値と演算子を受け取ります。入力された数値と演算子に基づいて計算を行い、結果をシリアルモニタに表示します。
使用例:
Arduinoをコンピュータに接続し、Arduino IDEのシリアルモニタを開きます。
シリアルモニタに数値、演算子、数値の形式で入力します(例: 5 + 3)。
シリアルモニタに計算結果が表示されます。
このプログラムは単純な例であり、エラーハンドリングや追加の機能は含まれていません。必要に応じて機能を追加し、エラーチェックや拡張した計算機能を実装することができます。
Appy Pie: Appy Pieは、ビジネス、イベント、教育、eコマースなど、さまざまな種類のアプリを簡単に作成できるオンラインサービスです。サービスに登録すると、豊富なテンプレートやカスタマイズツールを利用して、簡単にAndroidアプリを作成できます。
Thunkable: Thunkableは、ドラッグアンドドロップのUIビルダーと、ビジュアルプログラミング言語を使用して、簡単にAndroidアプリを作成できるオンラインサービスです。また、独自のコードを書くこともできます。
AppMakr: AppMakrは、ブログ、ニュースサイト、eコマースサイトなどから、簡単にAndroidアプリを作成できるオンラインサービスです。ユーザーフレンドリーなUIビルダーを備えており、カスタマイズも簡単にできます。
tes1
│├
非公開
Number-plus.tcl
│├
非公開
renamer-x
│├
非公開
test-calc2
│├
非公開
test-calc
│├
非公開
arduino-memo
│├
非公開
test1
│├
非公開
めも
│├
http://retropc.net/cisc/m88/dl/obsolete/
8898emu
│├
すぽなー
1332 78 765
X
8
7
123456
■
■■■
-1368 69 -79 で すぽなー
960 107 -169
川川川
■■■■■■■■■■■■■■
■■■■■■■■■■■■■■■■■■
■■■■■■■■■■■■■■■
896 107 -111 ■■960 107 -111 ■■ 1100 107 -111
■■■■■■■■■■■■
■■■■■■■■■■■
960 107 -70
653 76 398
1484 13 -49 スケルトンのスポナ
1588 73 -111 いりぐちあけられそう
697 24 571 スケルトンスポナ
901 18 466 スケルトンスポナ
875 36 815 毒蜘蛛スポナ
まいくら
│├
$folder = "test";
use File::Find;
use Cwd;
my $dir=cwd() . "/" . $folder;
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);$mon += 1;$year += 1900;
my $dir2=cwd() . "/" . $folder . "_" . "$year$mon$mday";
print "$dir2\n";
@data1 = ();
$dfile = "date--.txt";
find(\&print_file, $dir);
sub print_file {
$file = $_;
$path = $File::Find::name;
@stat_inf = stat $path;
$fsize =$stat_inf[7];
($mday,$mon,$year) = (localtime($stat_inf[9]))[3..5];$mon += 1;$year += 1900;
$fddd = "$year年$mon月$mday日";
if ($fsize != 0) {push @data1,"$path,$year年,$mon月,$mday日"};
}
printf "@data1";
$line = <STDIN>;
open(OUT, ">$dfile");
foreach $ddd ( @data1 ) {print OUT "$ddd\n";};close(OUT);
memo---perl
│├
非公開
★Todo
│└
非公開
WEB−XRの情報など
├
javascript shortcode area
└
postnote
・その場でjavascriptの編集
実行、デバッグOK
・ツリー管理
・変数管理
・括弧の色分け(オマケ程度)
・無限Undo
・完全オリジナルの環境です。
・このCGIのお問い合わせは
・momonga-v4.live.jp まで。