2026年7月20日月曜日

How to transfer root bone pose animation to the animation of the entire armature 5.x

 import bpy

import math


from mathutils import Matrix

from bpy_extras import anim_utils



# ============================================================

# Settings

# ============================================================


ROOT_BONE_NAME = "Root"


# If True:

#   Bake a keyframe on every frame between the first and last

#   root bone keyframe.

#   This preserves interpolation more accurately, but creates

#   many additional keyframes.

#

# If False:

#   Process only frames that already contain root bone keys.

#   This behaves similarly to the original version of the script.

BAKE_EVERY_FRAME = False


# Delete the root bone after the transfer is complete.

DELETE_ROOT_BONE = True



# ============================================================

# Blender 5.x / Legacy Action Compatibility

# ============================================================


def get_action_fcurves(animated_id):

    """

    Return all F-Curves from the Action currently assigned

    to the specified animated datablock.


    Blender 4.x and earlier:

        action.fcurves


    Blender 5.x:

        Action Slot

            -> Channelbag

                -> F-Curves

    """


    animation_data = animated_id.animation_data


    if animation_data is None:

        return []


    action = animation_data.action


    if action is None:

        return []


    # Legacy Blender API.

    if hasattr(action, "fcurves"):

        return list(action.fcurves)


    # Blender 5.x layered Action API.

    action_slot = getattr(animation_data, "action_slot", None)


    # Normally animation_data.action_slot is available.

    # As a fallback, use the only slot if the Action has exactly one.

    if action_slot is None:

        slots = getattr(action, "slots", None)


        if slots is not None and len(slots) == 1:

            action_slot = slots[0]


    if action_slot is None:

        print(

            f"Warning: No Action slot was found for "

            f"'{animated_id.name}'."

        )

        return []


    channelbag = anim_utils.action_get_channelbag_for_slot(

        action,

        action_slot

    )


    if channelbag is None:

        return []


    return list(channelbag.fcurves)



def collect_keyframes(fcurves, data_path_prefix=None):

    """

    Collect all unique keyframe times from a list of F-Curves.


    If data_path_prefix is specified, only F-Curves whose

    data paths start with that prefix are included.

    """


    frames = set()


    for fcurve in fcurves:

        if (

            data_path_prefix is not None

            and not fcurve.data_path.startswith(data_path_prefix)

        ):

            continue


        for keyframe in fcurve.keyframe_points:

            frames.add(float(keyframe.co.x))


    return sorted(frames)



def set_scene_frame(scene, frame):

    """

    Set the current timeline position with subframe support,

    then update the dependency graph.

    """


    whole_frame = math.floor(frame)

    subframe = frame - whole_frame


    scene.frame_set(whole_frame, subframe=subframe)

    bpy.context.view_layer.update()



# ============================================================

# Main

# ============================================================


scene = bpy.context.scene


# Store the original timeline position so it can be restored later.

original_frame = scene.frame_current + scene.frame_subframe


# Use the currently active object as the source armature.

armature = bpy.context.active_object


if armature is None or armature.type != 'ARMATURE':

    raise ValueError("Please select an armature object.")


bpy.context.view_layer.objects.active = armature

armature.select_set(True)


# Switch to Object Mode before reading transforms.

if armature.mode != 'OBJECT':

    bpy.ops.object.mode_set(mode='OBJECT')



# ============================================================

# Validate Root Bone

# ============================================================


root_pose_bone = armature.pose.bones.get(ROOT_BONE_NAME)


if root_pose_bone is None:

    raise ValueError(

        f"Root bone '{ROOT_BONE_NAME}' was not found."

    )


root_data_bone = armature.data.bones.get(ROOT_BONE_NAME)


if root_data_bone is None:

    raise ValueError(

        f"Root data bone '{ROOT_BONE_NAME}' was not found."

    )



# ============================================================

# Store Root Bone Rest Transform

# ============================================================


armature_matrix_world = armature.matrix_world.copy()

root_bone_matrix_rest = root_data_bone.matrix_local.copy()


root_bone_matrix_world_rest = (

    armature_matrix_world

    @ root_bone_matrix_rest

)


(

    root_bone_default_loc,

    root_bone_default_rot,

    root_bone_default_scale

) = root_bone_matrix_world_rest.decompose()


inverse_root_bone_default_rot = (

    root_bone_default_rot.inverted()

)



# ============================================================

# Collect IK Targets

# ============================================================


ik_targets = []


for pose_bone in armature.pose.bones:

    for constraint in pose_bone.constraints:


        if constraint.type != 'IK':

            continue


        target = constraint.target


        if target is None:

            continue


        # Only process external IK target objects parented

        # to the selected armature.

        if target.parent != armature:

            continue


        # Prevent duplicate targets from being added.

        if target not in ik_targets:

            ik_targets.append(target)



# ============================================================

# Store Original IK Target World Positions

# ============================================================


ik_target_keyframes = {}


for target in ik_targets:

    target_fcurves = get_action_fcurves(target)

    target_frames = collect_keyframes(target_fcurves)


    ik_target_keyframes[target.name] = {}


    for frame in target_frames:

        set_scene_frame(scene, frame)


        ik_target_keyframes[target.name][frame] = (

            target.matrix_world.translation.copy()

        )



# ============================================================

# Get Armature Action

# ============================================================


animation_data = armature.animation_data


if animation_data is None:

    raise ValueError("Animation data was not found.")


action = animation_data.action


if action is None:

    raise ValueError("No Action is assigned to the armature.")


armature_fcurves = get_action_fcurves(armature)


if not armature_fcurves:

    raise ValueError(

        "No F-Curves were found in the armature Action."

    )



# ============================================================

# Collect Root Bone Keyframes

# ============================================================


root_data_path_prefix = (

    f'pose.bones["{ROOT_BONE_NAME}"]'

)


root_keyframes = collect_keyframes(

    armature_fcurves,

    root_data_path_prefix

)


if not root_keyframes:

    raise ValueError(

        f"No animation keys were found for "

        f"root bone '{ROOT_BONE_NAME}'."

    )


# Optionally bake every integer frame between

# the first and last root bone keyframe.

if BAKE_EVERY_FRAME:

    first_frame = math.floor(min(root_keyframes))

    last_frame = math.ceil(max(root_keyframes))


    sample_frames = [

        float(frame)

        for frame in range(first_frame, last_frame + 1)

    ]


else:

    sample_frames = root_keyframes



# ============================================================

# Sample Root Bone Transforms

#

# At this stage, transforms are only recorded.

# No keys are written to the armature object yet.

#

# This prevents newly inserted armature object keyframes

# from affecting transform evaluation on later frames.

# ============================================================


transform_data = {}


for frame in sample_frames:

    set_scene_frame(scene, frame)


    # PoseBone.matrix is expressed in armature object space.

    root_bone_matrix = root_pose_bone.matrix.copy()


    # Convert the root bone transform to world space.

    global_matrix = (

        armature.matrix_world

        @ root_bone_matrix

    )


    global_loc, global_rot, global_scale = (

        global_matrix.decompose()

    )


    transform_data[frame] = {

        "location": global_loc.copy(),

        "rotation": global_rot.copy(),

        "scale": global_scale.copy(),

    }



# ============================================================

# Bake the Root Bone Transform to the Armature Object

# ============================================================


bpy.ops.object.mode_set(mode='OBJECT')


# Quaternion rotation avoids Euler angle discontinuities

# during the transfer.

armature.rotation_mode = 'QUATERNION'


translation_matrix_to_default = Matrix.Translation(

    -root_bone_default_loc

)


for frame in sample_frames:

    data = transform_data[frame]


    loc = data["location"]

    rot = data["rotation"]

    scale = data["scale"]


    # Remove the root bone's rest rotation.

    corrected_rot = (

        rot

        @ inverse_root_bone_default_rot

    )


    translation_matrix_current = Matrix.Translation(loc)

    rotation_matrix = corrected_rot.to_matrix().to_4x4()


    # Apply the same transform order as the original script:

    #   1. Translate relative to the root bone's rest location.

    #   2. Apply the corrected root bone rotation.

    #   3. Move to the current root bone location.

    final_matrix = (

        translation_matrix_current

        @ rotation_matrix

        @ translation_matrix_to_default

    )


    final_loc, final_rot, _ = final_matrix.decompose()


    armature.location = final_loc

    armature.rotation_quaternion = final_rot

    armature.scale = scale


    armature.keyframe_insert(

        data_path="location",

        frame=frame

    )


    armature.keyframe_insert(

        data_path="rotation_quaternion",

        frame=frame

    )


    armature.keyframe_insert(

        data_path="scale",

        frame=frame

    )



# ============================================================

# Preserve IK Target World Positions

# ============================================================


for target in ik_targets:

    saved_frames = ik_target_keyframes.get(target.name, {})


    for frame, initial_world_position in saved_frames.items():

        set_scene_frame(scene, frame)


        # Convert the stored world-space position back into

        # the target's armature-relative local space using

        # the armature transform at the current frame.

        local_position = (

            armature.matrix_world.inverted()

            @ initial_world_position

        )


        target.location = local_position


        target.keyframe_insert(

            data_path="location",

            frame=frame

        )



# ============================================================

# Delete Root Bone

# ============================================================


if DELETE_ROOT_BONE:

    bpy.context.view_layer.objects.active = armature

    armature.select_set(True)


    bpy.ops.object.mode_set(mode='EDIT')


    edit_root_bone = armature.data.edit_bones.get(

        ROOT_BONE_NAME

    )


    if edit_root_bone is not None:

        armature.data.edit_bones.remove(edit_root_bone)


    bpy.ops.object.mode_set(mode='OBJECT')



# ============================================================

# Restore Original Timeline Position

# ============================================================


set_scene_frame(scene, original_frame)


print(

    f"Finished. Root bone animation has been transferred "

    f"to the armature object '{armature.name}'."

)


2026年7月19日日曜日

Privacy Policy for Living Diorama

Privacy Policy for Living Diorama

Last updated: 19 July 2026

Living Diorama respects your privacy.

Data Collection

Living Diorama does not collect, store, transmit or share any personal information or usage data.

The app does not collect information such as:

  • Names or contact details

  • Location data

  • Device identifiers

  • Usage or interaction data

  • Photos, videos or audio

  • Health or fitness data

  • Purchase information

Interactions with animals, food and other elements within the app are not recorded or transmitted to the developer.

Analytics, Advertising and Tracking

Living Diorama does not use third-party analytics services, advertising networks or tracking technologies.

The app does not track users across apps or websites and does not display personalised advertising.

Third-Party Data Sharing

Living Diorama does not share user data with third parties because the app does not collect user data.

Data Storage and Deletion

Living Diorama does not store personal information on external servers.

As no personal information is collected or retained by the developer, there is no personal data to access, export or delete.

Children’s Privacy

Living Diorama does not knowingly collect personal information from children or any other users.

Changes to This Privacy Policy

This Privacy Policy may be updated if the app’s features or data practices change. Any changes will be published on this page, together with an updated revision date.


2026年7月8日水曜日

Swipe to Collapse - A Quantum Wave Game

 Overview

Swipe to Collapse is a single-player iPhone game and interactive quantum wave simulation.

This app displays a real-time simulation of the Schrödinger equation using compute shaders.

A quantum wave function lives on the grid. Its colour is the phase and its brightness is how likely the particle is to be there (|ψ|²). You play by observing it.

App purpose and target audience

The app lets users play with a quantum wave function. The color represents phase, and the brightness represents probability density, |ψ|². Users interact with the wave by dragging across the field to observe a selected region. When the user releases, the wave function collapses probabilistically according to the Born rule.

The app is designed for users who enjoy physics-inspired games, experimental arcade games, and interactive science visualizations. Its value is to turn abstract quantum concepts such as observation, probability density, phase, wave function collapse, and position/momentum representations into an interactive visual experience.

The app is intended for entertainment and educational exploration. It is not a professional scientific, medical, financial, or regulated-industry tool.

Observe

Drag across the field to outline a region, then let go to measure it. The wave collapses by the Born rule — the particle is either found inside your region (it snaps bright there) or not (that area goes dark). Pick a stage and try it freely before starting a game.

Game

Tap Start for a 30-second round. Green particles roam the field and score continuously — the brighter the wave |ψ| where a particle sits, the faster it scores. Observe (drag) to collapse the wave and pile it onto the green particles. Red particles (stage 2+) drain your score the same way, so keep the wave dark around them. Best 3 scores per stage are saved. Tap × to quit.

Z/pZ Lab — position & momentum together

An experimental mode on the finite set Z/pZ, where position and momentum are both finite and the Fourier transform links them. Two strips show \psi(x) and \hat{\psi}(k) at once — drag either one to observe in that basis. The carpet below charts the wave over time; watch the fractal revivals. Switch p, potential, kinetic term, initial state and more.

2026年7月5日日曜日

Privacy Policy for Swipe to Collapse

 Privacy Policy

Effective Date: July 5, 2026

This Privacy Policy applies to Swipe to Collapse, an iPhone app developed by Junnichi Suko.

No Data Collection

Swipe to Collapse does not collect, store, transmit, or share personal data with the developer or any third party.

The app does not collect or transmit:

  • Name
  • Email address
  • Location data
  • Contacts
  • Photos or videos
  • Audio recordings
  • Device identifiers
  • Advertising identifiers
  • Analytics data
  • User-generated content

Local Game Data

The app may save certain game data locally on your device, such as game progress or high scores.

This data is stored only on your device and is not transmitted to the developer or to any external server.

If you delete the app, this locally stored data may also be deleted.

No Advertising or Tracking

The app does not display advertisements.

The app does not use third-party advertising networks.

The app does not track users across apps, websites, or services.

No Third-Party Analytics

The app does not use third-party analytics or crash reporting services.

Internet Connection

Core gameplay does not require an internet connection.

The app does not send personal information or gameplay data to the developer or to any external server.

Children’s Privacy

The app does not knowingly collect any personal information from children or adults.

Changes to This Privacy Policy

This Privacy Policy may be updated in the future if the app’s features change.

If the app ever begins collecting data, this Privacy Policy will be updated to describe what data is collected, how it is used, and any choices available to users.

Contact

If you have any questions about this Privacy Policy, please contact:

junichistamesi@gmail.com

2026年5月20日水曜日

Spatial Sound Magic Privacy Policy

 Last updated: May 20, 2026

This app does not collect, store, transmit, or share any personal data.

The app uses the microphone, hand tracking, and room interaction features only to provide its core spatial audio experience. Voice input, recorded audio, hand interactions, and room-based effects are processed locally on your device.

If you record audio in the app, the recording is used only within the app experience. Audio recordings are not uploaded to any server, sent to the developer, or shared with third parties.

This app does not use analytics, advertising, tracking technologies, or third-party data collection services.

We do not collect:

  • Personal information
  • Audio data
  • Speech data
  • Room or spatial mapping data
  • Hand tracking data
  • Device identifiers
  • Location data
  • Usage analytics

Because no personal data is collected, there is no personal data for us to sell, share, or disclose.

Spatial Sound Magic

This app turns your voice, hands, walls, and room into a playful spatial musical instrument.

Tap the Show Immersive Space button to enter an interactive spatial sound experience.

When you speak, colorful sound orbs are launched forward into your room (Up to 30 pieces). Each orb changes its color based on the pitch of your voice and its size based on the volume. When a sound orb bounces off the room collision mesh, that part of the room mesh temporarily becomes visible and plays a tone based on the orb’s color.

You can also interact with sound directly using your hands. Touch a sound orb to make it play a tone and disappear. Touch a wall, or use gaze and pinch toward a wall, to make the wall glow and play a pitch based on the height of the touched position.

The app also includes voice recording. Tap the Record button to record your voice(Up to 20 files). From the bottom area of the main menu, you can open the recorded audio list, play back your recordings, or tap the 3D Cube button to visualize a recording above your left palm. The recorded sound becomes a 3D audio sculpture, where thickness represents volume and color represents pitch. Turn your palm downward to detach the sculpture from your hand.

You can play the sculpture like a physical music object. Stroke the sculpture up and down with your left or right fingers, and the touched section will play back its corresponding sound, like pins on a music box or a playback bar moving through audio.

Turn on Comic Mode to transform speech into an American comic-style speech bubble experience. The app recognizes spoken language and launches 3D alphabet characters into space.

In Theremin Mode, your hand position and gestures generate sound in real time. Closing your hand lowers the volume. Theremin Mode can be toggled separately for the left and right hands.


2025年3月4日火曜日

Spatial Birds


https://apps.apple.com/us/app/spatial-birds/id6742704318

Full Feature List - 


1. Start Scene (Bounded Mode)

  • Tap the Play button to start interacting with the birds.
  • If the Tutorial Mode button is enabled, instructions will be displayed while playing with the birds.
  • Use the Hide UI button to hide the start screen’s UI panel.
    This allows you to display only the birdcage as a decorative element in your room.
    Tap the sphere at the top of the birdcage to show the UI again.
  • In the start scene, you cannot grab the birds.
    However, you can pinch and drag an acorn close to a bird.
    The bird will eat the acorn, chirp, and fly away.
    After flying for a while, it will perch on a branch again.

2. Interactive Bird Scene (Unbounded Mode - Requires Hand Tracking & Room Detection)

  • At the start, the birdcage disappears, and the birds take flight.
  • Extend your finger and wait for a bird to approach.
    The bird will perch on your finger and look at you.
  • If a bird moves more than 3 metres away, it will respawn near the camera to keep interactions engaging.
  • Look at your left wrist and tap the Menu button to open the main menu.
    In the main menu, you can:
    • Toggle the visibility of each bird species: European robin, budgerigar, and Japanese white-eye.
    • Remove all acorns.
    • Show or hide perches.
    • Adjust the volume of flapping and chirping sounds.
    • Return to the start scene.
    • Display the control instructions.
  • Bring your index fingers and thumbs together to create an acorn.
  • You can move perches, acorns, and birds using gaze + pinch and drag.
  • In Tutorial Mode, the following actions will be explained in sequence:
    • How to let a bird perch on your finger.
    • How to access the menu.
    • How to create an acorn.
      After completing these steps for the first time, Tutorial Mode will be disabled.

Spatial Birds privacy policy

Our app does not collect, store, or share any personal information from users.

Data Not Collected:

  • Contact Information (name, email address, etc.)
  • Health and Fitness Information
  • Financial Information
  • Location Data
  • Sensitive Information
  • User Content (photos, videos, audio data, etc.)
  • Browsing and Search History
  • Identifiers (user ID, device ID)
  • Usage Data
  • Diagnostic Data
  • Environmental Scanning Data
  • Physical Data

Our app does not collect data on hand movements, gaze positions, or any other gameplay-related data.

2024年12月5日木曜日

Pteranodon Document



 Demo Scene Usage: In the demo scene, you can control the Pteranodon's third-person character by playing the scene in the Play In Editor mode. You can randomly change morphs by pressing 'O' and alter the color randomly by pressing 'B'. 

2024年9月18日水曜日

Spatial Pose Recorder

https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=6695755455

 Spatial Pose Recorder: Capture and Visualize Motion in Space

support mail:junichistamesi@gmail.com

Overview:
Spatial Pose Recorder is an app that captures and records the movements of your hands and head in a spatial environment. With the ability to record up to 60 poses, this app offers a unique way to visualize and animate your motions.

Key Features:

Record up to 60 poses of hand and head movements
Adjustable recording intervals from 0.1 to 5 seconds
Visualize recorded poses in space or play them back as animations
Save up to 5 sets of recorded pose sequences (Each set can contain up to 60 poses)

Detailed Functionality:

Recording:
• Press the "Start Recording" button to initiate a 4-second countdown before recording begins
• Default setting: Records 30 poses over 6 seconds (0.2-second intervals)
Visualization:
• After recording, press the "Visualize" button to display recorded poses
• Color-coded visualization:

Left hand: Red to light blue
Right hand: Blue to yellow
Head: Green to purple
• Press "Animate" to play back the recorded sequence

Time Settings:
• Customize recording duration, interval, and playback speed
• Preset options:
6 seconds (0.2-second intervals)
30 seconds (1-second intervals)
180 seconds (3-second intervals)
• Use slider for custom settings (up to 60 poses, where Duration/Interval ≤ 60)

Save and Load:
• Save recordings in 5 available slots
• View save date and time for each slot
• Delete unwanted recordings
User Interface:
• Toggle menu panel visibility using the left-hand menu button
• Access "Stop Recording" during active recording to save partial sequences