This commit is contained in:
syui 2024-06-03 23:47:02 +09:00
parent 20ea7a92b8
commit d58d548c95
Signed by: syui
GPG Key ID: 5417CFEBAD92DF56
74 changed files with 1598 additions and 33 deletions

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
*/*-lock.json
*/node_modules
*.sqlite
*.lock
*target
*.db
**.DS_Store
*.DS_Store
/scpt/*.jpeg
/scpt/*.png
config

View File

@ -0,0 +1,52 @@
<!DOCTYPE HTML>
<html style="width: 100%; height: 100%">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Optional: apply a font -->
<!--
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Michroma&family=Montserrat:wght@600&display=swap" rel="stylesheet">
-->
<!-- Optional: set some favicons -->
<link rel="shortcut icon" href="43ef81525e6853dc.ico" type="image/x-icon">
<link rel="icon" type="image/png" sizes="96x96" href="images/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="32x32" href="images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="images/favicon-16x16.png">
<!-- Optional: set a title for your page -->
<title>Pixel Streaming</title>
<script defer src="player.js"></script></head>
<!-- The Pixel Streaming player fills 100% of its parent element but body has a 0px height unless filled with content. As such, we explicitly force the body to be 100% of the viewport height -->
<body style="width: 100vw; height: 100vh; min-height: -webkit-fill-available; font-family: 'Montserrat'; margin: 0px">
<style>
button#settingsBtn {
display:none;
}
button#statsBtn {
display:none;
}
button#fullscreen-btn {
display:none;
}
div#connection{
display:none;
}
.comment {
text-align: right;
padding: 10px;
}
a{
text-decoration: none;
color: #ccc;
}
</style>
<div class="comment">
<a href="https://bsky.app/profile/yui.syui.ai/feed/cmd">/comment</a>
</div>
</body>
</html>

View File

@ -0,0 +1,13 @@
services:
restreamer:
image: datarhei/restreamer
#image: datarhei/restreamer:cuda-latest
ports:
- 8080:8080
- 1935:1935
- 6000:6000/udp
restart: always
volumes:
- ./data/config:/core/config
- ./data/data:/core/data

View File

@ -0,0 +1,11 @@
[package]
name = "rust-bbs"
version = "0.1.0"
edition = "2021"
[dependencies]
actix-web = "4.0"
url = "2.3.1"
rusqlite = { version = "0.28", features = ["bundled"] }
serde = { version = "1.0", features = ["derive"] }
askama = "*"

View File

@ -0,0 +1,8 @@
FROM syui/aios
WORKDIR /app
COPY ./src ./src
COPY ./templates ./templates
COPY ./Cargo.toml ./Cargo.toml
RUN cargo build --release
CMD ["/app/target/release/rust-bbs"]

View File

@ -0,0 +1,7 @@
services:
web:
build: .
ports:
- 8080:8080
volumes:
- ./sqlite.db:/app/sqlite.db

127
github/rust-bbs/src/main.rs Normal file
View File

@ -0,0 +1,127 @@
use askama::Template;
use serde::{Deserialize, Serialize};
use rusqlite::{Connection, Result as SqliteResult};
use actix_web::{web, App, HttpServer, HttpResponse, Responder, HttpRequest, Error};
use actix_web::error::{ErrorInternalServerError};
use std::fmt;
impl fmt::Display for Post {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "@{} {}", self.handle.as_deref().unwrap_or("anonymous"), self.content)
}
}
#[derive(Deserialize, Default)]
struct QueryParams {
handle: Option<String>,
}
#[derive(Serialize, Deserialize)]
struct Post {
id: i32,
handle: Option<String>,
content: String,
}
#[derive(Template)]
#[template(path = "index.html")]
struct IndexTemplate {
posts: Vec<Post>,
}
#[derive(Template)]
#[template(path = "post.html")]
struct PostTemplate {}
fn init_db() -> SqliteResult<()> {
let conn = Connection::open("sqlite.db")?;
conn.execute(
"CREATE TABLE IF NOT EXISTS posts (
id INTEGER PRIMARY KEY,
handle TEXT NOT NULL,
content TEXT NOT NULL
)",
[],
)?;
Ok(())
}
async fn index() -> impl Responder {
let conn = Connection::open("sqlite.db").unwrap();
let mut stmt = conn.prepare("SELECT id, handle, content FROM posts ORDER BY id DESC").unwrap();
let posts = stmt.query_map([], |row| {
Ok(Post {
id: row.get(0)?,
handle: row.get(1)?,
content: row.get(2)?,
})
}).unwrap().filter_map(Result::ok).collect::<Vec<Post>>();
let template = IndexTemplate { posts };
HttpResponse::Ok().body(template.render().unwrap())
}
async fn post_form() -> impl Responder {
let template = PostTemplate {};
HttpResponse::Ok().body(template.render().unwrap())
}
#[derive(Deserialize)]
struct FormData {
handle: String,
content: String,
}
async fn submit_post(
req: HttpRequest,
form: web::Form<FormData>
) -> Result<impl Responder, Error> {
let query = web::Query::<QueryParams>::from_query(req.query_string())
.unwrap_or_else(|_| web::Query(QueryParams { handle: None }));
//let handle = query.handle.clone().filter(|h| !h.is_empty());
//println!("Debug: Extracted handle: {:?}", handle);
let handle = if !form.handle.is_empty() {
form.handle.clone()
} else {
query.handle.clone().unwrap_or_default()
};
println!("Debug: Using handle: {:?}", handle);
let conn = Connection::open("sqlite.db")
.map_err(|_| ErrorInternalServerError("Database connection failed"))?;
let result = conn.execute(
"INSERT INTO posts (handle, content) VALUES (?1, ?2)",
&[&form.handle, &form.content],
);
match result {
Ok(_) => {
let redirect_url = if !handle.is_empty() {
format!("/?handle={}", handle)
} else {
"/".to_string()
};
Ok(HttpResponse::SeeOther()
.append_header(("Location",
redirect_url))
.finish())
},
//Ok(_) => Ok(web::Redirect::to("/" + "?handle=" + handle).see_other()),
Err(_) => Err(ErrorInternalServerError("Failed to insert post")),
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
init_db().unwrap();
HttpServer::new(|| {
App::new()
.route("/", web::get().to(index))
.route("/post", web::get().to(post_form))
.route("/submit", web::post().to(submit_post))
})
.bind("0.0.0.0:8080")?
.run()
.await
}

View File

@ -0,0 +1,79 @@
<!DOCTYPE html>
<html>
<head>
<title>Simple BBS</title>
</head>
<body>
<div class="post-form" id="post-form">
<form action="/submit" method="post">
<input type="hidden" name="handle" id="handleInput">
<textarea name="content" required></textarea>
<input type="submit" value="Post">
</form>
</div>
<div class="post-list">
<ul>
{% for post in posts %}
<li><span class="user-post">{{ post }}</span></li>
{% endfor %}
</ul>
</div>
</body>
<script>
function getHandleFromUrl() {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get('handle');
}
window.onload = function() {
const handle = getHandleFromUrl();
if (handle) {
document.getElementById('handleInput').value = handle;
} else {
document.getElementById('handleInput').value = "anonymous";
var post = document.getElementById('post-form');
post.style.display = 'none';
}
};
</script>
<style>
ul {
overflow-y: scroll;
white-space: normal;
word-break: break-word;
}
li {
width: 100%;
list-style: none;
padding: 10px 0px;
border-bottom: 1px solid #ccc;
}
textarea {
width: 100%;
border-radius: 5px;
resize: none;
border-bottom: 3px solid #2060df;
box-sizing: border-box;
}
input[type="submit"] {
border-radius: 5px;
width: 100%;
color: #fff;
background: #2060df;
border: none;
padding: 10px;
font-size 20px;
}
ul {
border-radius: 5px;
padding: 0px;
margin: 0 auto;
border: 1px solid #ccc;
}
span.user-post {
padding: 0px 10px;
}
</style>
</html>

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<title>New Post</title>
</head>
<body>
<h1>New Post</h1>
<form action="/submit" method="post">
<textarea name="content" required></textarea>
<br>
<input type="submit" value="Post">
</form>
</body>
</html>

7
github/slidev/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
node_modules
.DS_Store
dist
*.local
.vite-inspect
.remote-assets
components.d.ts

3
github/slidev/.npmrc Normal file
View File

@ -0,0 +1,3 @@
# for pnpm
shamefully-hoist=true
auto-install-peers=true

15
github/slidev/README.md Normal file
View File

@ -0,0 +1,15 @@
# Welcome to [Slidev](https://github.com/slidevjs/slidev)!
To start the slide show:
- `npm install`
- `npm run dev`
- visit <http://localhost:3030>
Edit the [slides.md](./slides.md) to see the changes.
Learn more about Slidev at the [documentation](https://sli.dev/).
```sh
$ slidev build --base /slide
```

View File

@ -0,0 +1,37 @@
<script setup lang="ts">
import { ref } from 'vue'
const props = defineProps({
count: {
default: 0,
},
})
const counter = ref(props.count)
</script>
<template>
<div flex="~" w="min" border="~ main rounded-md">
<button
border="r main"
p="2"
font="mono"
outline="!none"
hover:bg="gray-400 opacity-20"
@click="counter -= 1"
>
-
</button>
<span m="auto" p="2">{{ counter }}</span>
<button
border="l main"
p="2"
font="mono"
outline="!none"
hover:bg="gray-400 opacity-20"
@click="counter += 1"
>
+
</button>
</div>
</template>

View File

@ -0,0 +1,16 @@
[build]
publish = "dist"
command = "npm run build"
[build.environment]
NODE_VERSION = "20"
[[redirects]]
from = "/.well-known/*"
to = "/.well-known/:splat"
status = 200
[[redirects]]
from = "/*"
to = "/index.html"
status = 200

View File

@ -0,0 +1,17 @@
{
"name": "slidev",
"type": "module",
"private": true,
"scripts": {
"build": "slidev build",
"dev": "slidev --open",
"export": "slidev export"
},
"dependencies": {
"@slidev/cli": "^0.49.29",
"@slidev/theme-default": "latest",
"@slidev/theme-seriph": "latest",
"slidev-theme-eloc": "^1.0.2",
"vue": "^3.4.38"
}
}

View File

@ -0,0 +1,27 @@
# Imported Slides
You can split your slides.md into multiple files and organize them as you want using the `src` attribute.
#### `slides.md`
```markdown
# Page 1
Page 2 from main entry.
---
## src: ./subpage.md
```
<br>
#### `subpage.md`
```markdown
# Page 2
Page 2 from another file.
```
[Learn more](https://sli.dev/guide/syntax.html#importing-slides)

135
github/slidev/slides.md Normal file
View File

@ -0,0 +1,135 @@
---
theme: eloc
class: text-center
highlighter: shiki
lineNumbers: false
info: |
## Slidev Starter Template
Presentation slides for developers.
Learn more at [Sli.dev](https://sli.dev)
drawings:
persist: false
transition: slide-left
title: Unreal Engine 5.5 | aiue
---
# `aiue`
物語は空と海に囲まれた西の都(みやこ)からはじまる...
---
## 配信で使える最新技術の紹介
### `unreal engine`
- vrm4u, vmc, livelink, streaming
- chatgpt, atproto
- `ai` + `ue`
---
## `unreal engine`
- ue 5.5.0p
- ue 5.4.4
---
## `vrm4u`
キャラクターを表示しよう
---
`vmc`と`livelink`で体の動きを反映
- vmcはABP
- livelinkはCBP
---
## `web browser`
WBPからwebを使おう
---
- widget3dをworldに表示させると画質が悪いので`EngineMaterials/Widget3DPassThrough`以外のmaterialを使います
<iframe src="https://blueprintue.com/render/-49_059w/"></iframe>
https://blueprintue.com/blueprint/-49_059w/
---
## `pixel streaming`
webでゲーム配信や操作ができる
```sh
$ git clone https://github.com/EpicGamesExt/PixelStreamingInfrastructure
$ cd ./PixelStreamingInfrastructure/SignallingWebServer/platform_scripts/cmd/
$ ./Start_SignallingServer_nopublic.ps1
```
---
## `atproto`
blueskyが使っているprotocol
---
## `game animation sample`
キャラクターの基本操作をカスタマイズ
---
## `city sample`
人や車が動く最先端の街
---
## `ultra dynamic sky`
- `sky atmoshpere` + `volumetric cloud`
---
## `whisper` + `chatgpt` + `elevenlabs`
キャラ設定と会話
- whisper : RuntimeSpeechRecognizer
---
```sh
# perplexity.ai
$ curl -X POST "https://api.elevenlabs.io/v1/text-to-speech/VOICE_ID" \
-H "xi-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Hello world!",
"model_id": "eleven_monolingual_v1",
"voice_settings": {
"stability": 0.5,
"similarity_boost": 0.5
}
}' \
--output output.mp3
```
---
@syui.ai
<br/>
<img src="https://yui.syui.ai/icon/ai.svg" width="50px">
<!--
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/7/7a/Bluesky_Logo.svg/1200px-Bluesky_Logo.svg.png" width="30px">
-->

View File

@ -0,0 +1,12 @@
/* eslint-disable no-console */
// #region snippet
// Inside ./snippets/external.ts
export function emptyArray<T>(length: number) {
return Array.from<T>({ length })
}
// #endregion snippet
export function sayHello() {
console.log('Hello from snippets/external.ts')
}

View File

@ -0,0 +1,7 @@
{
"rewrites": [
{ "source": "/(.*)", "destination": "/index.html" }
],
"buildCommand": "npm run build",
"outputDirectory": "dist"
}

BIN
img/issue-9-0001.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

BIN
img/issue-9-0002.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
img/issue-9-0003.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 792 KiB

BIN
img/issue-9-0004.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 960 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

BIN
img/wiki-frontpage-0001.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

View File

@ -0,0 +1,125 @@
{
"lexicon": 1,
"id": "ai.syui.game.user",
"defs": {
"main": {
"type": "record",
"key": "tid",
"description": "Record containing a game user.",
"input": {
"encoding": "application/json",
"record": {
"type": "object",
"required": [
"did",
"createdAt"
],
"properties": {
"aiten": {
"type": "integer",
"default": 0
},
"limit": {
"type": "bool"
},
"login": {
"type": "bool"
},
"did": {
"type": "string"
},
"handle": {
"type": "string"
},
"gender": {
"type": "string",
"enum": [
"none",
"male",
"famale"
]
},
"charactor": {
"type": "object",
"enum": [ "ai", "chinese", "manny", "quinn", "phoenix", "kirin", "leviathan", "wyvern", "cerberus", "dragon", "kitsune", "pegasus" ],
"properties": {
"type": "object",
"properties": {
"season": {
"type": "integer",
"default": 0
},
"group": {
"type": "string",
"default": "origin"
},
"img": {
"type": "uri",
"default": "https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:4hqjfn7m6n5hno3doamuhgef/bafkreie34pjuc6coenzcdwrgrh4fbacq7bkhsz263g5vpbsqxwaz37kkwy@jpeg"
},
"lv": {
"type": "integer",
"minimum": 1,
"maximum": 7,
"default": 1
},
"exp": {
"type": "integer"
},
"hp": {
"type": "integer",
"maximum": 255,
"default": 0
},
"attach": {
"type": "integer",
"minimum": 1,
"maximum": 255,
"default": 0
},
"attach_post": {
"type": "integer",
"default": 0
},
"critical": {
"type": "integer",
"minimum": 0,
"maximum": 255,
"default": 0
},
"critical_d": {
"type": "integer",
"minimum": 0,
"maximum": 255,
"default": 0
},
"rank": {
"type": "integer",
"minimum": 0,
"maximum": 7,
"default": 0
},
"mode": {
"type": "integer",
"minimum": 0,
"maximum": 3,
"default": 0
}
}
}
}
},
"createdAt": {
"type": "string",
"format": "datetime",
"description": "Client-declared timestamp when this post was originally created."
},
"updatedAt": {
"type": "string",
"format": "datetime"
}
}
}
}
}
}

View File

@ -0,0 +1,56 @@
--- ./VMC4UE/VMC4UE/Source/VMC4UE/Source/VMC4UEBlueprintFunctionLibrary.cpp
+++ ./VMC4UEBlueprintFunctionLibrary.cpp
@@ -119,27 +119,29 @@ UVMC4UEStreamingSkeletalMeshTransform* UVMC4UEBlueprin
{
return nullptr;
}
-
+
+ UVMC4UEStreamingSkeletalMeshTransform* StreamingSkeletalMeshTransform = nullptr;
+
+ // Try to get existing transform
{
- // Get
FRWScopeLock RWScopeLock(OSCManager->RWLock, FRWScopeLockType::SLT_ReadOnly);
- auto StreamingSkeletalMeshTransform = OSCManager->StreamingSkeletalMeshTransformMap.Find(Port);
- if (StreamingSkeletalMeshTransform != nullptr)
+ auto FoundTransform = OSCManager->StreamingSkeletalMeshTransformMap.Find(Port);
+ if (FoundTransform != nullptr)
{
- return *StreamingSkeletalMeshTransform;
+ return *FoundTransform;
}
}
+
+ // Create new transform if not found
{
- // Create
FRWScopeLock RWScopeLock(OSCManager->RWLock, FRWScopeLockType::SLT_Write);
- auto StreamingSkeletalMeshTransform = OSCManager->StreamingSkeletalMeshTransformMap.Find(Port);
- if (StreamingSkeletalMeshTransform != nullptr)
+ auto FoundTransform = OSCManager->StreamingSkeletalMeshTransformMap.Find(Port);
+ if (FoundTransform != nullptr)
{
- return *StreamingSkeletalMeshTransform;
+ return *FoundTransform;
}
- UVMC4UEStreamingSkeletalMeshTransform* NewStreamingSkeletalMeshTransform = NewObject<UVMC4UEStreamingSkeletalMeshTransform>();
- //FRWScopeLock RWScopeLock2(NewStreamingSkeletalMeshTransform->RWLock, FRWScopeLockType::SLT_Write);
+ UVMC4UEStreamingSkeletalMeshTransform* NewStreamingSkeletalMeshTransform = NewObject<UVMC4UEStreamingSkeletalMeshTransform>();
OSCManager->StreamingSkeletalMeshTransformMap.Emplace(Port, NewStreamingSkeletalMeshTransform);
// Bind Port
@@ -149,9 +151,10 @@ UVMC4UEStreamingSkeletalMeshTransform* UVMC4UEBlueprin
OSCManager->OscReceivers.Emplace(OscReceiver);
- return NewStreamingSkeletalMeshTransform;
+ StreamingSkeletalMeshTransform = NewStreamingSkeletalMeshTransform;
}
- return nullptr;
+
+ return StreamingSkeletalMeshTransform;
}
void UVMC4UEBlueprintFunctionLibrary::RefreshConnection(float Seconds)

View File

@ -0,0 +1,25 @@
--- ./VMC4UE/Source/VMC4UEEd/Source/VMC4UEBoneMappingAssetFactory.cpp
+++ ./VMC4UEBoneMappingAssetFactory.cpp
@@ -5,6 +5,8 @@
#include "../../VMC4UE/Include/VMC4UEStreamingData.h"
#include "Dom/JsonObject.h"
#include "JsonObjectConverter.h"
+#include "UObject/ConstructorHelpers.h"
+#include "UObject/UObjectGlobals.h"
UVMC4UEBoneMappingAssetFactory::UVMC4UEBoneMappingAssetFactory(const FObjectInitializer &ObjectInitializer)
: Super(ObjectInitializer)
@@ -26,11 +28,12 @@
return UVMC4UEVRMMapping::StaticClass();
}
+
UObject *UVMC4UEBoneMappingAssetFactory::FactoryCreateText(UClass *InClass, UObject *InParent, FName InName, EObjectFlags Flags, UObject *Context, const TCHAR *Type, const TCHAR *&Buffer, const TCHAR *BuferEnd, FFeedbackContext *Warn)
{
FString TextData = FString(Buffer);
- UVMC4UEVRMMapping *NewAsset = CastChecked<UVMC4UEVRMMapping>(StaticConstructObject_Internal(InClass, InParent, InName, Flags));
+ UVMC4UEVRMMapping* NewAsset = NewObject<UVMC4UEVRMMapping>(InParent, InClass, InName, Flags);
if (!IsValid(NewAsset))
{
return nullptr;

23
plugins/vmc4ue/readme.md Normal file
View File

@ -0,0 +1,23 @@
vmc4ue patch rebuild for `ue5.4`
- https://github.com/HAL9HARUKU/VMC4UE
- https://github.com/HAL9HARUKU/ueOSC
- https://github.com/HAL9HARUKU/VRMMapExporter
- https://github.com/vrm-c/UniVRM
[unity](https://unity.com/)で`VRMMapExporter`から`$model.vrmmap`を作る。ABPで読み込む。
`VMC4UE`は`$project.sln`を生成して`visual studio solution`でrebuildする。
ただし、この方法で表情を動かすことはできない。
```sh
$ git clone https://github.com/HAL9HARUKU/VMC4UE
$ cd VMC4UE
$ git reset --hard b5a6cf96e5928551d8e3e20b74705e3e8f22a1df
$ cd ..
# example
$ patch -u ./VMC4UE/VMC4UE/Source/VMC4UE/Source/VMC4UEBlueprintFunctionLibrary.cpp < VMC4UEBlueprintFunctionLibrary.cpp.patch
$ patch -u ./VMC4UE/VMC4UE/Source/VMC4UEEd/Source/VMC4UEBoneMappingAssetFactory.cpp < VMC4UEBoneMappingAssetFactory.cpp.patch
```

112
readme.md
View File

@ -1,41 +1,87 @@
# yui
- pixel streaming : https://ue.syui.ai
- support : `windows 64bit`
|title|推奨スペック|
|---|---|
|cpu|AMD Ryzen 7 5700X|
|memory|32GB / DDR4-3200 DIMM (PC4-25600)|
|gpu|GeForce RTX 4060Ti 8GB|
|storage|1TB M.2 NVMe SSD|
ハイスペックなパソコンが必要です。
## help
web板は同じ画面と操作が共有されています。他の人がログインしてプレイしているときは邪魔しないようにしましょう。
## download & start
ダウンロードは数時間かかります。
```sh
# ダウンロード
$ git clone https://git.syui.ai/ai/ue
$ cd ue
# 解凍
$ aunpack yui.zip
# 実行
$ ./Windows/yui.exe
```
[aiverse](https://git.syui.ai/ai/ue/wiki/verse) project.
## log
|version|commit|
|---|---|
|v0.1 β|世界を作っているところ|
|v0.2 β|物語を作った。webに対応|
|v0.1 β|world create|
|v0.2 β|support web|
|v0.3 β|support vmc|
|v0.4 β|support at|
## at
the player data is stored in the pds.
```sh
├── [yui.syui.ai]
│   ├── ai.syui.game.user
│   │   ├── lv
│   │   ├── hp
│   │   └── coin
│   └── ai.syui.game.login
│   ├── login <bool>
│   ├── updatedAt
│   └── username
└─── [user.bsky.social]
   └── ai.syui.game
      ├── account <at://yui.syui.ai...>
      └── createdAt
```
```sh
# https://git.syui.ai/ai/at/src/branch/main/at.zsh
$ ./at.zsh u at://did:plc:4hqjfn7m6n5hno3doamuhgef/ai.syui.game.user/syui
{
"uri": "at://did:plc:4hqjfn7m6n5hno3doamuhgef/ai.syui.game.user/syui",
"cid": "bafyreigijd4vonyzgjkzotrbtq5j5gyoecokoij3u7jw4sqnx6wkh7attq",
"value": {
"did": "did:plc:uqzpqmrjnptsxezjx4xuh2mn",
"$type": "ai.syui.game.user",
"aiten": 0,
"limit": false,
"login": false,
"gender": "male",
"handle": "syui.ai",
"character": {
"ai": {
"hp": 9,
"lv": 1,
"exp": 0,
"img": "https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:4hqjfn7m6n5hno3doamuhgef/bafkreie34pjuc6coenzcdwrgrh4fbacq7bkhsz263g5vpbsqxwaz37kkwy@jpeg",
"mode": 0,
"rank": 0,
"group": "origin",
"attach": 0,
"season": 0,
"critical": 1,
"critical_d": 0,
"attach_post": 14102
}
},
"createdAt": "2024-11-29T21:34:27.833Z",
"updatedAt": "2024年12月8日 11:25:17 GMT"
}
}
```
## service
|title|url|
|---|---|
|game|https://ue.syui.ai|
|live|https://live.syui.ai|
|chat|https://o.syui.ai|
## support
`windows 64bit`
|title|spec|
|---|---|
|cpu|AMD Ryzen 7 5700X|
|memory|32GB / DDR4-3200 DIMM (PC4-25600)|
|gpu|GeForce RTX 4060Ti 8GB|
|storage|1TB M.2 NVMe SSD|

169
scpt/character.zsh Executable file
View File

@ -0,0 +1,169 @@
#!/bin/zsh
function download_character_icon(){
t=(
"https://sketchfab.com/3d-models/super-9a80a6d6cf6f4b08906505c7f945d3ce"
)
t=(
"https://sketchfab.com/3d-models/cerberus-quirky-series-4379b571b5a440119d1ebaddb0711142"
"https://sketchfab.com/3d-models/chinese-dragon-quirky-series-a383d3cf5b004978ac620806558b2924"
"https://sketchfab.com/3d-models/dragon-quirky-series-9a0989aae9b84ebdade28e84a0702a71"
"https://sketchfab.com/3d-models/kirin-quirky-series-b280c8bc5b87471eac1068acc91fdce1"
"https://sketchfab.com/3d-models/kitsune-quirky-series-4fc8b2ade43f4d4bb8a8e6e227f00a62"
"https://sketchfab.com/3d-models/leviathan-quirky-series-002200e1db2c461fbcaa8d2fdac2d766"
"https://sketchfab.com/3d-models/pegasus-quirky-series-a4488ae7a2d2405c927a50f5a8b2d6bb"
"https://sketchfab.com/3d-models/phoenix-quirky-series-1f0a01247b78441ab5b9cf8e9711e78e"
"https://sketchfab.com/3d-models/wyvern-quirky-series-7baad217325a45b4877514b3f5924be9"
)
for i in $t; do
name=`echo $i|cut -d / -f 5|cut -d - -f 1`
tt=`curl -sL $i|tr ' ' '\n' |grep .jpeg|cut -d '"' -f 2`
normal=`echo $tt|awk "NR==1"`
min=`echo $tt|awk "NR==2"`
if [ ! -f $name.jpeg ];then
curl -sL $normal -o $name.jpeg
fi
if [ ! -f ${name}-min.jpeg ];then
#curl -sL $min -o ${name}-min.jpeg
fi
array+=(`echo $tt|sed "1,2d"|cut -d ";" -f 2|cut -d '&' -f 1|tr '\n' ' '`)
echo $name
for ((i=1; i<=$#array; i++)); do
#echo "Index: $i, Value: ${array[$i]}"
#curl -sL ${array[$i]} -o ${name}-${i}.jpeg
done
done
}
handle_yui=yui.syui.ai
did_yui=did:plc:4hqjfn7m6n5hno3doamuhgef
token_yui=`cat ~/.config/ai/token.json|jq -r .accessJwt`
host=bsky.social
case $OSTYPE in
darwin*)
day=`gdate --iso-8601=seconds`
;;
*)
day=`date --iso-8601=seconds`
;;
esac
function create_game_character() {
t=(
ai
chinese
kirin
leviathan
phoenix
wyvern
cerberus
dragon
kitsune
pegasus
)
for ((i=1; i<=$#t; i++)); do
created=2001-01-01T00:00:00+09:00
col=ai.syui.game.character
req=com.atproto.repo.getRecord
url=https://$host/xrpc/$req
id=$i
name=${t[$i]}
chara=$name
rkey=$chara
repo=$did_yui
json="{\"collection\":\"$col\", \"rkey\":\"$rkey\", \"repo\":\"$repo\"}"
if [ $((RANDOM % 2)) -eq 0 ];then
gender=male
else
gender=female
fi
case $name in
ai)
gender=none
group=origin
season=0
;;
chinese|dragon|cerberus|pegasus|leviathan)
gender=male
group=fantasy
season=1
;;
kitsune|phoenix|kirin|wyvern)
gender=female
group=fantasy
season=1
;;
*)
continue ;;
esac
jj=`curl -sL "$url?repo=$repo&collection=$col&rkey=$rkey"`
link=`echo $jj|jq -r '.value.embed.external.thumb.ref.[]'`
size=`echo $jj|jq -r .value.embed.external.thumb.size`
mtype=`echo $jj|jq -r .value.embed.external.thumb.mimeType`
echo $name
echo $gender
echo https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:4hqjfn7m6n5hno3doamuhgef/$link
## upload img
#if [ -f ./${name}.jpeg ];then
# jj=`ai img-upload ./${name}.jpeg`
#elif [ -f ./${name}.png ];then
# jj=`ai img-upload ./${name}.png`
#fi
#link=`echo $jj|jq -r ".blob.ref.[]"`
#size=`echo $jj|jq -r .blob.size`
#mtype=`echo $jj|jq -r .blob.mimeType`
req=com.atproto.repo.putRecord
url=https://$host/xrpc/$req
nickname=$name
fullname=$name
uri=at://${did_yui}/$col/$chara
json="{
\"repo\": \"$handle_yui\",
\"did\": \"$did_yui\",
\"collection\": \"$col\",
\"rkey\": \"$chara\",
\"record\": {
\"id\": $id,
\"name\": \"$name\",
\"fullname\": \"$fullname\",
\"nickname\": \"$nickname\",
\"gender\": \"$gender\",
\"season\": $season,
\"group\": \"$group\",
\"embed\": {
\"\$type\": \"app.bsky.embed.external\",
\"external\": {
\"uri\": \"$uri\",
\"thumb\": {
\"\$type\": \"blob\",
\"ref\": {
\"\$link\": \"$link\"
},
\"mimeType\": \"$mtype\",
\"size\": $size
} } }, \"createdAt\": \"$created\", \"updatedAt\": \"$day\" } }"
if echo $json|jq . ;then
curl -sL -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $token_yui" -d $json $url
fi
done
}
#download_character_icon
create_game_character

BIN
texture/T__02.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

427
ue.json Normal file
View File

@ -0,0 +1,427 @@
{
"aiue": {
"name": "ue",
"body": {
"text": "ai unreal engine, game naming conventions, character attribute",
"lang": {
"ja": "AI Unreal Engine, ゲームの命名規則, キャラクターの属性"
}
},
"tag": [
"ai",
"atom",
"molecule",
"atmosphere",
"universe"
],
"ai": {
"name": "ai",
"group": [
"origin"
],
"lang": {
"ja": "アイ"
},
"ref": "at://syui.ai",
"body": {
"text": "the smallest unit in this world, smaller than a quark. the smaller it is, the more it can gather together. it generates enormous gravity, and black holes are made up of these particles. this world is the world of existence. existence is made up of the consciousness of existence. the consciousness of existence is the smallest thing in this world, and all matter is a collection of this consciousness.",
"lang": {
"ja": "クォークよりも小さいこの世界の最小単位。小さいほど集まることができる。膨大な重力が発生し、ブラックホールはこの粒子で構成されている。この世界は存在の世界。存在は存在の意識で構成される。存在の意識はこの世界で最も小さいもので、あらゆる物質はこの意識の集合体"
}
},
"tag": [
"ai",
"yui"
],
"ai": {
"name": "ai",
"color": "#fff700",
"lang": {
"ja": "アイ"
},
"story": {
"body": {
"text": "there is nothing the same in this world. even though we may seem to be looking at the same thing, we are actually looking at something different. there is uniqueness in everything",
"lang": {
"ja": "この世に同じものは何一つない。同じものを見ているように見えても、実は違うものを見ている。すべての存在は唯一性を持つ"
}
}
}
},
"yui": {
"name": "yui",
"color": "#313131",
"lang": {
"ja": "ユイ"
}
}
},
"atom": {
"name": "atom",
"group": [
"fantasy"
],
"lang": {
"ja": "原子"
},
"ref": "https://en.wikipedia.org/wiki/atom",
"body": {
"text": "the word atom comes from the greek word atmos, which means indivisible. an atom consists of an atomic nucleus, which is made up of protons and neutrons, and electrons distributed around the nucleus",
"lang": {
"ja": "アトムはギリシャ語のアトモス、これ以上分割できないという単語が由来。原子は陽子と中性子からなる原子核と、その周囲に分布する電子から構成される"
}
},
"tag": [
"proton",
"neutron",
"atomic",
"electron",
"quark"
],
"proton": {
"name": "proton",
"color": "#e74c3c",
"lang": {
"ja": "陽子"
}
},
"neutron": {
"name": "neutron",
"color": "#cacfd2",
"lang": {
"ja": "中性子"
}
},
"atomic": {
"name": "atomic",
"color": "#1abc9c",
"lang": {
"ja": "核"
}
},
"electron": {
"name": "electron",
"color": "#3498db",
"lang": {
"ja": "電子"
}
},
"quark": {
"name": "quark",
"color": "#9b59b6",
"lang": {
"ja": "クォーク"
}
},
"molecule": {
"name": "molecule",
"group": [
"animal"
],
"lang": {
"ja": "分子"
},
"ref": "https://en.wikipedia.org/wiki/molecule",
"body": {
"text": "a neutrally charged substance made up of two or more atoms",
"lang": {
"ja": "2つ以上の原子から構成される電荷的に中性な物質"
}
},
"tag": [
"water",
"wind",
"rock",
"ice",
"fire"
],
"water": {
"name": "water",
"color": "#blue",
"lang": {
"ja": "水"
}
},
"fire": {
"name": "fire",
"color": "#red",
"lang": {
"ja": "火"
}
},
"wind": {
"name": "wind",
"color": "#green",
"lang": {
"ja": "風"
}
},
"rock": {
"name": "rock",
"color": "#black",
"lang": {
"ja": "岩"
}
},
"ice": {
"name": "ice",
"color": "#white",
"lang": {
"ja": "氷"
}
}
}
},
"atmosphere": {
"name": "atmo",
"lang": {
"ja": "大気圏"
},
"exoshere": {
"name": "exo",
"lang": {
"ja": "外気圏"
},
"km": [
{
"min": 700,
"max": 10000
}
],
"tag": [
"universe"
]
},
"thermoshere": {
"name": "thermo",
"lang": {
"ja": "熱圏"
},
"km": [
{
"min": 80,
"max": 700
}
],
"tag": [
"aurora"
]
},
"mesoshere": {
"name": "meso",
"lang": {
"ja": "中間圏"
},
"km": [
{
"min": 50,
"max": 80
}
],
"tag": [
"meteor"
]
},
"stratoshere": {
"name": "strato",
"lang": {
"ja": "成層圏"
},
"km": [
{
"min": 12,
"max": 50
}
],
"tag": [
"ozone"
]
},
"troposhere": {
"name": "tropo",
"lang": {
"ja": "対流圏"
},
"km": [
{
"min": 0,
"max": 12
}
],
"tag": [
"sky"
]
},
"ref": "https://en.wikipedia.org/wiki/atmosphere_of_earth"
},
"universe": {
"name": "universe",
"lang": {
"ja": "宇宙"
},
"ref": "https://en.wikipedia.org/wiki/universe",
"tag": [
"earth",
"moon",
"sun",
"mercury",
"venus",
"mars",
"jupiter",
"saturn",
"uranus",
"neptune",
"neutronstar",
"blackhole",
"galaxy"
],
"earth": {
"name": "earth",
"lang": {
"ja": "地球"
},
"mass": 1.0
},
"moon": {
"name": "moon",
"lang": {
"lang": {
"ja": "月"
},
"mass": 0.0123
},
"sun": {
"name": "sun",
"tag": [
"solar"
],
"lang": {
"ja": "太陽"
},
"mass": 333000.01
},
"mars": {
"name": "mars",
"lang": {
"ja": "火星"
},
"mass": 0.107
},
"mercury": {
"name": "mercury",
"lang": {
"ja": "水星"
},
"mass": 0.055
},
"venus": {
"name": "venus",
"lang": {
"ja": "金星"
},
"mass": 0.815
},
"jupiter": {
"name": "jupiter",
"lang": {
"ja": "木星"
},
"mass": 317.8
},
"saturn": {
"name": "saturn",
"lang": {
"ja": "土星"
},
"mass": 95.16
},
"uranus": {
"name": "uranus",
"lang": {
"ja": "天王星"
},
"mass": 14.54
},
"neptune": {
"name": "neptune",
"lang": {
"ja": "海王星"
},
"mass": 17.15
},
"neutronstar": {
"name": "neutronstar",
"lang": {
"ja": "中性子星"
},
"mass": 466666.0
},
"blackhole": {
"name": "blackhole",
"lang": {
"ja": "ブラックホール"
},
"mass": 1000000000000.0
},
"galaxy": {
"name": "galaxy",
"ref": "https://en.wikipedia.org/wiki/galaxy",
"lang": {
"ja": "銀河"
},
"tag": [
"milkyway",
"andromeda",
"bode",
"cigar",
"whirlpool",
"cartwheel",
"ringnebula"
],
"milkyway": {
"name": "milkyway",
"lang": {
"ja": "天の川"
}
},
"andromeda": {
"name": "andromeda",
"lang": {
"ja": "アンドロメダ"
}
},
"bode": {
"name": "bode's",
"lang": {
"ja": "ボーデ"
}
},
"cigar": {
"name": "cigar",
"lang": {
"ja": "葉巻"
}
},
"whirlpool": {
"name": "whirlpool",
"lang": {
"ja": "子持ち"
}
},
"cartwheel": {
"name": "cartwheel",
"lang": {
"ja": "車輪"
}
},
"ringnebula": {
"name": "ringnebula",
"lang": {
"ja": "環状"
}
}
}
}
}
}
}

BIN
verse/bgm/aiend.mp3 Normal file

Binary file not shown.

BIN
verse/bgm/aiend.wav Normal file

Binary file not shown.

BIN
verse/bgm/aihouse.mp3 Normal file

Binary file not shown.

BIN
verse/bgm/aihouse.wav Normal file

Binary file not shown.

BIN
verse/bgm/aiverse.mp3 Normal file

Binary file not shown.

BIN
verse/bgm/aiverse.wav Normal file

Binary file not shown.

BIN
verse/bgm/test.wav Normal file

Binary file not shown.

BIN
verse/img/aiverse.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

BIN
verse/img/ep.mdp Normal file

Binary file not shown.

BIN
verse/img/ep.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 KiB

BIN
verse/img/fantasy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 709 KiB

BIN
verse/img/fly.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
verse/img/mode_ai.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
verse/img/mode_ai.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 KiB

BIN
verse/img/mode_normal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 KiB

BIN
verse/img/pomudachi.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

BIN
verse/img/recoder.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

BIN
verse/img/shinka.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 KiB

BIN
verse/img/shinryu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

BIN
verse/img/ue.mdp Normal file

Binary file not shown.

BIN
verse/img/ue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 KiB

BIN
verse/img/wa.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
verse/img/wall.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

16
verse/md/ep.md Normal file
View File

@ -0,0 +1,16 @@
# syui・ai
(シュイ・アイ)
THE FUZZY ONE
|title|body|
|---|---|
|nickname|syai|
|age|∞|
|height|123cm|
|birthday|1/23|
|lang|ja & en|
|text|「hello ai !」 一つの言葉しか覚えられない。自分やリスナーのことをアイと呼ぶ。世界を作るのが趣味。普段は地球を歩き回っている。|
|en|"Hello Ai!" I can only remember one word. I call myself and my listeners Ai. My hobby is creating worlds. I usually walk around the Earth.|

54
verse/md/ue.md Normal file
View File

@ -0,0 +1,54 @@
# Unreal Engine 5.4 | 初めてのゲーム制作、世界を作る
## vrm4u
キャラクターを表示しよう。
## game animation sample
今後はこの形式が基本になりそう。
## city sample
最初に難易度と負荷を高くする。
## sky atmoshpere + volumetric cloud
`dynamic volumetric sky -> ultra dynamic sky`
## whisper + chatgpt + elevenlabs
- whisper : RuntimeSpeechRecognizer
```sh
# perplexity.ai
$ curl https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-4o-mini",
"messages": [{"role": "user", "content": "Your question here"}],
"temperature": 0.7
}'
```
```sh
# perplexity.ai
$ curl -X POST "https://api.elevenlabs.io/v1/text-to-speech/VOICE_ID" \
-H "xi-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Hello world!",
"model_id": "eleven_monolingual_v1",
"voice_settings": {
"stability": 0.5,
"similarity_boost": 0.5
}
}' \
--output output.mp3
```
## ue vs unity
ueは手順通りやっても動くことは稀。つまり、動かない。そのため情報も少ない。unityがおすすめ。

BIN
verse/music/aidream.mp3 Normal file

Binary file not shown.

BIN
verse/music/aimoon.mp3 Normal file

Binary file not shown.

BIN
verse/music/aimoon.wav Normal file

Binary file not shown.

BIN
verse/music/aipalette.mp3 Normal file

Binary file not shown.

26
verse/readme.md Normal file
View File

@ -0,0 +1,26 @@
# aiverse
aiverse project.
- https://youtube.com/@syai
## AI
```json
{
"music": "https://suno.com/@syui",
"anime": "https://domoai.app",
"3d": "https://tripo3d.ai"
}
```
## ref
- [octoverse](https://octoverse.github.com/)
- [hololive](https://hololive.hololivepro.com/talents?gp=myth)
##
character, lyrics, composition, illustrations, game production, modeling, etc.
© syui

BIN
verse/video/op.mp4 Normal file

Binary file not shown.

BIN
verse/video/opload.mp4 Normal file

Binary file not shown.