0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

レイヤー型ノーコード システム ―アニメ制作用アプリを つくるためのアプリ―

Last updated at Posted at 2025-12-19

「レイヤー型Nocodeシステム」とは、 クリエイターがレイヤーを重ねることでプログラミングを行い、新たな映像表現や、映像制作ソフトを制作できるNocodeシステムです。
映像制作で用いる「レイヤー」を、「下の画像(入力値)を何かしら処理し、上のレイヤーに出力するモジュール」 と考え、制作しています。

現在開発中です。

Screenshot 2025-10-03 13.03.42.png
↑↑ブラーレイヤーをかけた画像
Screenshot 2025-09-28 15.37.52.png
↑↑処理に失敗したときのもの

❏ 利用目的

  • 映像制作、2Dアニメーション制作
  • 映像制作用ソフトウェアの開発

このソフトウェアは、短編アニメーション 『夜には止むよ』 の制作で利用することを目的としています。

❏ 動作環境

ブラウザ (テスト済み:Chrome)

❏ 目標

  • どのような機種でも実行できる(Webアプリ)
  • 必要最低限の機能を提供し、ユーザーがより柔軟に拡張利用・組み込みを行える
  • レイヤーを重ねる感覚でプログラミングができることで、クリエイターでも抵抗なくアプリケーションを作成できる

❏ 世界観

登場人物

物理レイヤー:一般的なペイントソフトでいうレイヤー。透明なセルをコンピュータ上で模したもの。

プログラムレイヤー:下にある画像(または他のデータ)を入力値として受け、それを処理して上の別のレイヤーに出力するモジュール

動作

https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_3658140_8f9a3028-b320-98f6-61d7-5246f90fd572.avif
↑プログラムレイヤー同士の関係

他のユーザーが作成した特定の動作をするプログラムレイヤーが存在する。これを複数重ねることによって、入力値の画像・映像を処理する。

また、プログラムレイヤーを重ね、物理レイヤーを作ることができる。物理レイヤーは、処理済みの生成物(画像)の透明度によって下の物理レイヤーが透けて見える。

物理レイヤー単位でイベントリスナーを付け、イベント発生時に、特定のレイヤーを更新することができる。

❏ 利用方法

プログラミング: YAMLファイルに、UI(ブラウザのオブジェクト)、重ねるレイヤーの順番、レイヤー同士のデータの紐づけを記入し、アプリケーションを作成

起動: システムを起動。作成したYAMLのファイル名を入力。

入力: 画像、動画を入力可能。それ以外はUI上で入力する。画像、映像は、ファイルを一つずつ選び、選んだ順番で配列に格納される。この現状は配列順序で映像のソース(材料)を指定する。

YAML記述方法

YAML.yaml
moduleAdr: ./modules/ # レイヤーが格納されているフォルダー住所

moduleNames: #利用可能なプログラムレイヤー(モジュール)を列挙
  - toGrayscale #0 ←この番号でモジュールを呼び出す
  - invertColors #1
  - edgeDetection #2
  - sharp #3
  - Blur #4
  - binerger #5
  - transparencyFilter #6
  - FloodFill #7
  - colorPicker.js #8
  - getMousePosition.js #9

# layerPは、複数のレイヤー定義を格納するリスト(配列)です。
# 全体を一つの `[]` で囲み、各レイヤー定義をカンマ `,` で区切ります。

layerP: [
  [
    [{uiId: A, event: click, function: V}], # ←ここでイベントリスナーを設定

    [{{layerNum: 9},{input: "phLayNum", for: 0}}], # レイヤー番号と、そのレイヤーに与える入力値

    [{{layerNum: 8},{from: 0}},{{layerNum: 9},{input: "phLayNum"}}], # このように2つのレイヤーを実行可能

    [{{layerNum: 7},{from: 0},{from: 1},{from: 2},{input: -1, from: CP},{num: 30}}] # 複数のモジュールからの出力も通しで0から番号が振られるfromで取得
  ]
]

ui: # 入力フォームの部品を作成
  - domId: A
    type: button
  - domId: B
    domName: B
    type: input
    inputType: radio
  - domId: D
    domName: B
    type: input
    inputType: radio
  - domId: C
    type: input
    inputType: number
  - domId: CP
    type: input
    inputType: color

以上のように、

  • プログラムレイヤーの列挙
  • レイヤーの重ね合わせ(物理レイヤー作成)
  • UI部品(フォーム部品)の指定

といった構成となっています。

特記

YAML.yaml.layerP

    [{{layerNum: 9},{input: "phLayNum", for: 0}}], 

以上は、layerPの2行目ですが、

YAML.yaml.layerP

    [{{layerNum: レイヤーの番号},{入力値①},{入力値②}}], 

というように読むことができます。
動かすレイヤー(モジュール)と、そこに入力する値を作成します。

入力値には、以下のようなオプションがあります。

YAML.yaml.layerP
{from: 番号} # 前のモジュールの出力配列の{番号}番目を入力

{input: "img", from: 番号} # 取得した複数のファイルの{番号}番目を入力

{input: "phLayNum"} # 現在処理している物理レイヤー(キャンバス)の番号を入力

{input: "UI", from: "ID"} # {ID}のファーム部品から値を取得して、それを入力

{input: "num", from: } # {数}を値として、そのまま入力

レイヤー(モジュール)定義

レイヤー(モジュール)は、様々なユーザーが作成したものを利用することを想定しています。
以下は、画像をある値で二値化するレイヤー。(読み飛ばしてください)

binarize.js
function binarize(imageData) {

  const width = imageData.width;
  const height = imageData.height;
  const outImageData = imageData.imageData;
  const threshold = imageData.threshold;

  // 入力値のチェック
  if (!(outImageData instanceof Uint8ClampedArray)) {
    throw new Error('imageData must be an Uint8ClampedArray');
  }
  if (typeof threshold !== 'number' || threshold < 0 || threshold > 255) {
    throw new Error('threshold must be a number between 0 and 255');
  }
  
  // 新しいUint8ClampedArrayを作成
  const data = new Uint8ClampedArray(outImageData.length);

  // 各ピクセルを処理
  for (let i = 0; i < outImageData.length; i += 4) {
    // 平均値を計算 (RGBの平均を使用)
     const average = (outImageData[i] + outImageData[i + 1] + outImageData[i + 2]) / 3;
     data[i] = data[i + 1] = data[i + 2] = average > threshold ? 255 : 0;
    // アルファ値はそのままコピー
    data[i + 3] = outImageData[i + 3];
  }
  
  return new ImageData(data, width, height);
}

// 静的プロパティとしてキーを定義
binarize.keys = {
  input: [
    { name: "imageData", type: "Uint8ClampedArray"},
    { name: "width", type: "number", "min": 0},
    { name: "height", type: "number", "min": 0},
    { name: "threshold", type: "number", min: "0", Mx: "255"} # 二値化する基準となる色
  ],
  comment: "",
  output: [
    { name: "data", type: "Uint8ClampedArray"},
    { name: "width", type: "number", "min": 0},
    { name: "height", type: "number", "min": 0}
  ]
};

export default binarize;

静的プロパティで、キーをレイヤー(モジュール)内で設定し、レイヤーシステム側で取得できるようにしています。

モジュールの入力値・出力値は、基本的に

  • Uint8ClampedArray
  • width
  • height
    の3つの値で画像をやり取りしています。

レイヤー(モジュール)は、様々な用途を考慮して、基本的にできるだけ小さな機能をパッケージングし、柔軟性をあげたものであってほしいです。

❏ 課題

  • ボックスを線で繋いでプログラミングできる映像ソフトは数多く存在し、わざわざレイヤー型のシステムを開発する必要があるのか?
     
  • ユーザーが複数の(出力値)-(入力値)間を紐づけ、データのやり取りを指定しなければ動かない →ボックス式のプログラミングのほうがわかりやすいのではないか?

❏ 開発状況

2025年5月:画像以外に入力値のあるモジュール(レイヤー)が使用可能に
2025年9月:モジュール(レイヤー)を組み合わせ、静止画の処理が可能に
2025年10月:物理レイヤー実装完了、複数の画像の入力が可能に
2025年11月:動画出力が可能に

現在、プログラマーが受験勉強中のため、昼休みに 細々コードを編んでいる状態です。
2025年11月に動画の処理が可能となった。柔軟性を高めるため、設計変更を加えています。この記事も仕様変更の都度書き換える予定です。完成は3月ごろになりそうです。
その頃までにはGithubに動作するバージョンを公開しようと考えているため、忘れていなければ のぞいて見てください。
また、コメント欄で、このソフトウェアの問題点や仕様についてのアドバイスを頂けると嬉しいです✨️

(※現在Githubにて「imageOS」として公開しているプログラムは最新バージョンではなく、動作しません。)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?