Files
AEmotionStudio-ComfyUI-Shad…/web/sampling_mode_migration.js
T
Æmotion StudioandClaude Opus 5 3af34338ab feat: add sampling_mode and route the node to the corrected pipeline
The Direct node now dispatches: "standard" (default) runs the new pipeline,
"legacy" runs the frozen pre-2.0 one. Measured through the node with a
recording sampler, 20 steps:

  standard, 1 stage       1 call  x 20 steps, from sigma 14.61
  standard, 2 stages      2 calls x 10 steps, from 14.61 then 1.48
  standard, denoise 0.6   1 call  x 20 steps, from 2.23
  standard, 3 injections  4 calls x  5 steps, 14.61 / 3.87 / 1.48 / 0.60
  legacy,   2 stages      2 calls, each rebuilding a full schedule

The 1.48 is the fix: stages continue one trajectory instead of restarting at
maximum noise, where flow models discard the previous stage entirely. The 2.23
is denoise finally reaching the schedule.

Also on the node:
- sequential_distribution, injection_distribution and fast_high_channel_noise
  become real optional inputs. As V1 `hidden` tuple inputs ComfyUI never
  delivered them, so they were stuck at their defaults.
- the debug/visualisation hidden inputs are gone; they drove stub no-ops.
- IS_CHANGED is removed: it only restated widget values that are already part
  of the cache key, and would have rejected the new input.
- new widgets are appended last, so saved workflows keep their widget order.

web/src/sampling_mode_migration.ts switches nodes loaded from pre-2.0
workflows to "legacy", recognising them by the absence of the snk_version
property, so existing seeds keep reproducing.

186 Python tests and 85 web tests pass; the 11 legacy goldens now exercise the
legacy branch through this dispatch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 15:35:14 -07:00

49 lines
2.0 KiB
JavaScript

// Import app from ComfyUI at runtime (this import is resolved by the browser)
// @ts-ignore - ComfyUI provides this at runtime
import { app } from '../../scripts/app.js';
const NODE_NAME = 'ShaderNoiseKSamplerDirect';
const SAMPLING_MODE_WIDGET = 'sampling_mode';
const VERSION_PROPERTY = 'snk_version';
const CURRENT_VERSION = 2;
/** True when this serialized node predates the sampling modes. */
export function needsLegacySampling(info) {
const properties = info?.properties;
return properties?.[VERSION_PROPERTY] === undefined;
}
/** Set the sampling_mode widget, if the node has one. */
export function setSamplingMode(node, mode) {
const widget = node.widgets?.find((w) => w.name === SAMPLING_MODE_WIDGET);
if (widget)
widget.value = mode;
}
/** Record that this node was written by a version that understands sampling modes. */
function stampVersion(node) {
node.properties = node.properties || {};
node.properties[VERSION_PROPERTY] = CURRENT_VERSION;
}
const extension = {
name: 'ShaderNoiseKSampler.SamplingModeMigration',
async beforeRegisterNodeDef(nodeType, nodeData, _app) {
if (nodeData.name !== NODE_NAME)
return;
const origOnNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function () {
if (origOnNodeCreated)
origOnNodeCreated.call(this);
stampVersion(this);
};
const origOnConfigure = nodeType.prototype.onConfigure;
nodeType.prototype.onConfigure = function (info) {
if (origOnConfigure)
origOnConfigure.call(this, info);
// Read the marker from the saved data, not from this.properties:
// onNodeCreated has already stamped the live node by this point.
if (needsLegacySampling(info)) {
setSamplingMode(this, 'legacy');
}
stampVersion(this);
};
},
};
app.registerExtension(extension);
//# sourceMappingURL=sampling_mode_migration.js.map